/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package com.xpn.xwiki;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DateFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TimeZone;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import java.util.zip.ZipOutputStream;
import javax.annotation.Priority;
import javax.inject.Provider;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.naming.NamingException;
import javax.script.ScriptContext;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.URIException;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.util.URIUtil;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.LocaleUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.velocity.VelocityContext;
import org.hibernate.HibernateException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xwiki.bridge.event.DocumentCreatedEvent;
import org.xwiki.bridge.event.DocumentCreatingEvent;
import org.xwiki.bridge.event.DocumentDeletedEvent;
import org.xwiki.bridge.event.DocumentDeletingEvent;
import org.xwiki.bridge.event.DocumentRolledBackEvent;
import org.xwiki.bridge.event.DocumentRollingBackEvent;
import org.xwiki.bridge.event.DocumentUpdatedEvent;
import org.xwiki.bridge.event.DocumentUpdatingEvent;
import org.xwiki.bridge.event.WikiCopiedEvent;
import org.xwiki.bridge.event.WikiDeletedEvent;
import org.xwiki.cache.Cache;
import org.xwiki.classloader.ClassLoaderManager;
import org.xwiki.component.event.ComponentDescriptorAddedEvent;
import org.xwiki.component.manager.ComponentLookupException;
import org.xwiki.component.manager.ComponentManager;
import org.xwiki.component.manager.NamespacedComponentManager;
import org.xwiki.component.util.DefaultParameterizedType;
import org.xwiki.configuration.ConfigurationSource;
import org.xwiki.context.Execution;
import org.xwiki.edit.EditConfiguration;
import org.xwiki.job.Job;
import org.xwiki.job.JobException;
import org.xwiki.job.JobExecutor;
import org.xwiki.job.annotation.Serializable;
import org.xwiki.job.event.status.JobProgressManager;
import org.xwiki.job.event.status.JobStatus.State;
import org.xwiki.localization.ContextualLocalizationManager;
import org.xwiki.mail.MailListener;
import org.xwiki.mail.MailSender;
import org.xwiki.mail.MailSenderConfiguration;
import org.xwiki.mail.MailStatusResultSerializer;
import org.xwiki.mail.XWikiAuthenticator;
import org.xwiki.model.EntityType;
import org.xwiki.model.reference.AttachmentReference;
import org.xwiki.model.reference.AttachmentReferenceResolver;
import org.xwiki.model.reference.DocumentReference;
import org.xwiki.model.reference.DocumentReferenceResolver;
import org.xwiki.model.reference.EntityReference;
import org.xwiki.model.reference.EntityReferenceResolver;
import org.xwiki.model.reference.EntityReferenceSerializer;
import org.xwiki.model.reference.LocalDocumentReference;
import org.xwiki.model.reference.ObjectReference;
import org.xwiki.model.reference.RegexEntityReference;
import org.xwiki.model.reference.SpaceReference;
import org.xwiki.model.reference.WikiReference;
import org.xwiki.observation.EventListener;
import org.xwiki.observation.ObservationManager;
import org.xwiki.observation.event.CancelableEvent;
import org.xwiki.observation.event.Event;
import org.xwiki.query.QueryException;
import org.xwiki.query.QueryFilter;
import org.xwiki.rendering.block.Block;
import org.xwiki.rendering.block.Block.Axes;
import org.xwiki.rendering.block.MetaDataBlock;
import org.xwiki.rendering.block.match.MetadataBlockMatcher;
import org.xwiki.rendering.internal.transformation.MutableRenderingContext;
import org.xwiki.rendering.listener.MetaData;
import org.xwiki.rendering.parser.ParseException;
import org.xwiki.rendering.syntax.Syntax;
import org.xwiki.rendering.syntax.SyntaxContent;
import org.xwiki.rendering.syntax.SyntaxFactory;
import org.xwiki.rendering.transformation.RenderingContext;
import org.xwiki.resource.ResourceReference;
import org.xwiki.resource.ResourceReferenceManager;
import org.xwiki.resource.ResourceReferenceResolver;
import org.xwiki.resource.ResourceType;
import org.xwiki.resource.ResourceTypeResolver;
import org.xwiki.resource.entity.EntityResourceReference;
import org.xwiki.script.ScriptContextManager;
import org.xwiki.skin.Resource;
import org.xwiki.skin.Skin;
import org.xwiki.skin.SkinManager;
import org.xwiki.template.TemplateManager;
import org.xwiki.url.ExtendedURL;
import org.xwiki.velocity.VelocityManager;
import org.xwiki.wiki.descriptor.WikiDescriptor;
import org.xwiki.wiki.descriptor.WikiDescriptorManager;
import org.xwiki.wiki.manager.WikiManager;
import org.xwiki.wiki.manager.WikiManagerException;
import org.xwiki.xml.XMLUtils;
import com.xpn.xwiki.api.Api;
import com.xpn.xwiki.api.Document;
import com.xpn.xwiki.api.User;
import com.xpn.xwiki.criteria.api.XWikiCriteriaService;
import com.xpn.xwiki.doc.DeletedAttachment;
import com.xpn.xwiki.doc.DocumentRevisionProvider;
import com.xpn.xwiki.doc.MandatoryDocumentInitializer;
import com.xpn.xwiki.doc.XWikiAttachment;
import com.xpn.xwiki.doc.XWikiDeletedDocument;
import com.xpn.xwiki.doc.XWikiDocument;
import com.xpn.xwiki.doc.XWikiDocument.XWikiAttachmentToRemove;
import com.xpn.xwiki.doc.XWikiDocumentArchive;
import com.xpn.xwiki.internal.WikiInitializerJob;
import com.xpn.xwiki.internal.WikiInitializerRequest;
import com.xpn.xwiki.internal.XWikiCfgConfigurationSource;
import com.xpn.xwiki.internal.XWikiConfigDelegate;
import com.xpn.xwiki.internal.XWikiInitializerJob;
import com.xpn.xwiki.internal.event.XObjectPropertyAddedEvent;
import com.xpn.xwiki.internal.event.XObjectPropertyDeletedEvent;
import com.xpn.xwiki.internal.event.XObjectPropertyEvent;
import com.xpn.xwiki.internal.event.XObjectPropertyUpdatedEvent;
import com.xpn.xwiki.internal.mandatory.XWikiPreferencesDocumentInitializer;
import com.xpn.xwiki.internal.render.OldRendering;
import com.xpn.xwiki.internal.render.groovy.ParseGroovyFromString;
import com.xpn.xwiki.internal.skin.InternalSkinConfiguration;
import com.xpn.xwiki.internal.skin.InternalSkinManager;
import com.xpn.xwiki.internal.skin.WikiSkin;
import com.xpn.xwiki.internal.skin.WikiSkinUtils;
import com.xpn.xwiki.job.JobRequestContext;
import com.xpn.xwiki.objects.BaseObject;
import com.xpn.xwiki.objects.PropertyInterface;
import com.xpn.xwiki.objects.classes.BaseClass;
import com.xpn.xwiki.objects.classes.PasswordClass;
import com.xpn.xwiki.objects.classes.PropertyClass;
import com.xpn.xwiki.objects.meta.MetaClass;
import com.xpn.xwiki.plugin.XWikiPluginInterface;
import com.xpn.xwiki.plugin.XWikiPluginManager;
import com.xpn.xwiki.render.groovy.XWikiPageClassLoader;
import com.xpn.xwiki.stats.api.XWikiStatsService;
import com.xpn.xwiki.stats.impl.SearchEngineRule;
import com.xpn.xwiki.stats.impl.XWikiStatsServiceImpl;
import com.xpn.xwiki.store.AttachmentRecycleBinStore;
import com.xpn.xwiki.store.AttachmentVersioningStore;
import com.xpn.xwiki.store.XWikiAttachmentStoreInterface;
import com.xpn.xwiki.store.XWikiCacheStore;
import com.xpn.xwiki.store.XWikiCacheStoreInterface;
import com.xpn.xwiki.store.XWikiHibernateStore;
import com.xpn.xwiki.store.XWikiRecycleBinStoreInterface;
import com.xpn.xwiki.store.XWikiStoreInterface;
import com.xpn.xwiki.store.XWikiVersioningStoreInterface;
import com.xpn.xwiki.user.api.XWikiAuthService;
import com.xpn.xwiki.user.api.XWikiGroupService;
import com.xpn.xwiki.user.api.XWikiRightService;
import com.xpn.xwiki.user.api.XWikiUser;
import com.xpn.xwiki.user.impl.xwiki.XWikiAuthServiceImpl;
import com.xpn.xwiki.user.impl.xwiki.XWikiGroupServiceImpl;
import com.xpn.xwiki.user.impl.xwiki.XWikiRightServiceImpl;
import com.xpn.xwiki.util.Util;
import com.xpn.xwiki.util.XWikiStubContextProvider;
import com.xpn.xwiki.web.Utils;
import com.xpn.xwiki.web.XWikiEngineContext;
import com.xpn.xwiki.web.XWikiMessageTool;
import com.xpn.xwiki.web.XWikiRequest;
import com.xpn.xwiki.web.XWikiURLFactory;
import com.xpn.xwiki.web.XWikiURLFactoryService;
import com.xpn.xwiki.web.XWikiURLFactoryServiceImpl;
import com.xpn.xwiki.web.includeservletasstring.IncludeServletAsString;
@Serializable(false)
public class XWiki implements EventListener
{
/** Name of the default wiki. */
public static final String DEFAULT_MAIN_WIKI = "xwiki";
/** Name of the default home space. */
public static final String DEFAULT_HOME_SPACE = "Main";
/** Name of the default system space. */
public static final String SYSTEM_SPACE = "XWiki";
/** Name of the default space homepage. */
public static final String DEFAULT_SPACE_HOMEPAGE = "WebHome";
public static final String CKEY_SKIN = InternalSkinManager.CKEY_SKIN;
public static final String CKEY_BASESKIN = InternalSkinManager.CKEY_PARENTSKIN;
public static final String DEFAULT_SKIN = InternalSkinConfiguration.DEFAULT_SKIN;
/** Logging helper object. */
protected static final Logger LOGGER = LoggerFactory.getLogger(XWiki.class);
/** Frequently used Document reference, the class which holds virtual wiki definitions. */
private static final DocumentReference VIRTUAL_WIKI_DEFINITION_CLASS_REFERENCE =
new DocumentReference(DEFAULT_MAIN_WIKI, SYSTEM_SPACE, "XWikiServerClass");
/** The default encoding, and the internally used encoding when dealing with byte representation of strings. */
public static final String DEFAULT_ENCODING = "UTF-8";
/** Represents no value (ie the default value will be used) in xproperties */
private static final String NO_VALUE = "---";
/** The main document storage. */
private XWikiStoreInterface store;
/** The attachment storage (excluding attachment history). */
private XWikiAttachmentStoreInterface attachmentStore;
/** Store for attachment archives. */
private AttachmentVersioningStore attachmentVersioningStore;
/** Document versioning storage. */
private XWikiVersioningStoreInterface versioningStore;
/** Deleted documents storage. */
private XWikiRecycleBinStoreInterface recycleBinStore;
/**
* Storage for deleted attachment.
*
* @since 1.4M1
*/
private AttachmentRecycleBinStore attachmentRecycleBinStore;
private XWikiPluginManager pluginManager;
private XWikiAuthService authService;
private XWikiRightService rightService;
private XWikiGroupService groupService;
private XWikiStatsService statsService;
private XWikiURLFactoryService urlFactoryService;
private XWikiCriteriaService criteriaService;
/** Lock object used for the lazy initialization of the authentication service. */
private final Object AUTH_SERVICE_LOCK = new Object();
/** Lock object used for the lazy initialization of the authorization service. */
private final Object RIGHT_SERVICE_LOCK = new Object();
/** Lock object used for the lazy initialization of the group management service. */
private final Object GROUP_SERVICE_LOCK = new Object();
/** Lock object used for the lazy initialization of the statistics service. */
private final Object STATS_SERVICE_LOCK = new Object();
/** Lock object used for the lazy initialization of the URL Factory service. */
private final Object URLFACTORY_SERVICE_LOCK = new Object();
private MetaClass metaclass;
private String version;
private XWikiEngineContext engine_context;
private String database;
private String fullNameSQL;
/**
* The list of initialized wikis.
*/
private Map<String, WikiInitializerJob> initializedWikis = new ConcurrentHashMap<>();
private boolean isReadOnly = false;
/**
* @deprecated since 6.1M2, use {@link XWikiCfgConfigurationSource#CFG_ENV_NAME} instead
*/
@Deprecated
public static final String CFG_ENV_NAME = XWikiCfgConfigurationSource.CFG_ENV_NAME;
public static final String MACROS_FILE = "/templates/macros.txt";
/**
* File containing XWiki's version, in the format: <version name>.<SVN revision number>.
*/
private static final String VERSION_FILE = "/WEB-INF/version.properties";
/**
* Property containing the version value in the {@link #VERSION_FILE} file.
*/
private static final String VERSION_FILE_PROPERTY = "version";
private static XWikiInitializerJob job;
/** List of configured syntax ids. */
private List<String> configuredSyntaxes;
/** Used to convert a proper Document Reference to string (standard form). */
private EntityReferenceSerializer<String> defaultEntityReferenceSerializer;
/**
* Used to resolve a string into a proper Document Reference using the current document's reference to fill the
* blanks, except for the page name for which the default page name is used instead.
*/
private DocumentReferenceResolver<String> currentMixedDocumentReferenceResolver;
private DocumentReferenceResolver<EntityReference> currentReferenceDocumentReferenceResolver;
private EntityReferenceResolver<String> currentMixedEntityReferenceResolver;
private EntityReferenceResolver<String> relativeEntityReferenceResolver;
private EntityReferenceSerializer<String> localStringEntityReferenceSerializer;
private SyntaxFactory syntaxFactory;
private ResourceReferenceManager resourceReferenceManager;
private JobExecutor jobExecutor;
private InternalSkinManager internalSkinManager;
private TemplateManager templateManager;
private RenderingContext renderingContext;
/**
* Whether backlinks are enabled or not (cached for performance).
*
* @since 3.2M2
*/
private Boolean hasBacklinks;
private ConfigurationSource xwikicfg;
private ConfigurationSource wikiConfiguration;
private ConfigurationSource userConfiguration;
private ConfigurationSource spaceConfiguration;
private EditConfiguration editConfiguration;
private ObservationManager observationManager;
private Provider<XWikiContext> xcontextProvider;
private ContextualLocalizationManager localization;
private Provider<OldRendering> oldRenderingProvider;
private ParseGroovyFromString parseGroovyFromString;
private JobProgressManager progress;
private Provider<DocumentReference> defaultDocumentReferenceProvider;
private DocumentReferenceResolver<EntityReference> currentgetdocumentResolver;
private AttachmentReferenceResolver<EntityReference> currentAttachmentReferenceResolver;
private WikiSkinUtils wikiSkinUtils;
private DocumentRevisionProvider documentRevisionProvider;
/**
* List of top level space names that can be used in the fake context document created when accessing a resource
* with the 'skin' action.
*/
private List<String> SKIN_RESOURCE_SPACE_NAMES = Arrays.asList("skins", "resources");
private ConfigurationSource getConfiguration()
{
if (this.xwikicfg == null) {
this.xwikicfg = Utils.getComponent(ConfigurationSource.class, XWikiCfgConfigurationSource.ROLEHINT);
}
return this.xwikicfg;
}
private ConfigurationSource getWikiConfiguration()
{
if (this.wikiConfiguration == null) {
this.wikiConfiguration = Utils.getComponent(ConfigurationSource.class, "wiki");
}
return this.wikiConfiguration;
}
private ConfigurationSource getSpaceConfiguration()
{
if (this.spaceConfiguration == null) {
this.spaceConfiguration = Utils.getComponent(ConfigurationSource.class, "space");
}
return this.spaceConfiguration;
}
private ConfigurationSource getUserConfiguration()
{
if (this.userConfiguration == null) {
this.userConfiguration = Utils.getComponent(ConfigurationSource.class, "user");
}
return this.userConfiguration;
}
private EditConfiguration getEditConfiguration()
{
if (this.editConfiguration == null) {
this.editConfiguration = Utils.getComponent(EditConfiguration.class);
}
return this.editConfiguration;
}
private InternalSkinManager getInternalSkinManager()
{
if (this.internalSkinManager == null) {
this.internalSkinManager = Utils.getComponent(InternalSkinManager.class);
}
return this.internalSkinManager;
}
private TemplateManager getTemplateManager()
{
if (this.templateManager == null) {
this.templateManager = Utils.getComponent(TemplateManager.class);
}
return this.templateManager;
}
private RenderingContext getRenderingContext()
{
if (this.renderingContext == null) {
this.renderingContext = Utils.getComponent(RenderingContext.class);
}
return this.renderingContext;
}
private MutableRenderingContext getMutableRenderingContext()
{
return getRenderingContext() instanceof MutableRenderingContext
? (MutableRenderingContext) getRenderingContext() : null;
}
private ObservationManager getObservationManager()
{
if (this.observationManager == null) {
this.observationManager = Utils.getComponent(ObservationManager.class);
}
return this.observationManager;
}
private XWikiContext getXWikiContext()
{
if (this.xcontextProvider == null) {
this.xcontextProvider = Utils.getComponent(XWikiContext.TYPE_PROVIDER);
}
return this.xcontextProvider.get();
}
private ContextualLocalizationManager getLocalization()
{
if (this.localization == null) {
this.localization = Utils.getComponent(ContextualLocalizationManager.class);
}
return this.localization;
}
private OldRendering getOldRendering()
{
if (this.oldRenderingProvider == null) {
this.oldRenderingProvider = Utils.getComponent(OldRendering.TYPE_PROVIDER);
}
return this.oldRenderingProvider.get();
}
private ParseGroovyFromString getParseGroovyFromString()
{
if (this.parseGroovyFromString == null) {
this.parseGroovyFromString = Utils.getComponent(ParseGroovyFromString.class);
}
return this.parseGroovyFromString;
}
private JobProgressManager getProgress()
{
if (this.progress == null) {
this.progress = Utils.getComponent(JobProgressManager.class);
}
return this.progress;
}
private Provider<DocumentReference> getDefaultDocumentReferenceProvider()
{
if (this.defaultDocumentReferenceProvider == null) {
this.defaultDocumentReferenceProvider = Utils.getComponent(DocumentReference.TYPE_PROVIDER);
}
return this.defaultDocumentReferenceProvider;
}
private DocumentReferenceResolver<EntityReference> getCurrentGetDocumentResolver()
{
if (this.currentgetdocumentResolver == null) {
this.currentgetdocumentResolver =
Utils.getComponent(DocumentReferenceResolver.TYPE_REFERENCE, "currentgetdocument");
}
return this.currentgetdocumentResolver;
}
private AttachmentReferenceResolver<EntityReference> getCurrentAttachmentResolver()
{
if (this.currentAttachmentReferenceResolver == null) {
this.currentAttachmentReferenceResolver =
Utils.getComponent(AttachmentReferenceResolver.TYPE_REFERENCE, "current");
}
return this.currentAttachmentReferenceResolver;
}
private EntityReferenceSerializer<String> getDefaultEntityReferenceSerializer()
{
if (this.defaultEntityReferenceSerializer == null) {
this.defaultEntityReferenceSerializer = Utils.getComponent(EntityReferenceSerializer.TYPE_STRING);
}
return this.defaultEntityReferenceSerializer;
}
private DocumentReferenceResolver<String> getCurrentMixedDocumentReferenceResolver()
{
if (this.currentMixedDocumentReferenceResolver == null) {
this.currentMixedDocumentReferenceResolver =
Utils.getComponent(DocumentReferenceResolver.TYPE_STRING, "currentmixed");
}
return this.currentMixedDocumentReferenceResolver;
}
private DocumentReferenceResolver<EntityReference> getCurrentReferenceDocumentReferenceResolver()
{
if (this.currentReferenceDocumentReferenceResolver == null) {
this.currentReferenceDocumentReferenceResolver =
Utils.getComponent(DocumentReferenceResolver.TYPE_REFERENCE, "current");
}
return this.currentReferenceDocumentReferenceResolver;
}
private EntityReferenceResolver<String> getCurrentMixedEntityReferenceResolver()
{
if (this.currentMixedEntityReferenceResolver == null) {
this.currentMixedEntityReferenceResolver =
Utils.getComponent(EntityReferenceResolver.TYPE_STRING, "currentmixed");
}
return this.currentMixedEntityReferenceResolver;
}
private EntityReferenceResolver<String> getRelativeEntityReferenceResolver()
{
if (this.relativeEntityReferenceResolver == null) {
this.relativeEntityReferenceResolver = Utils.getComponent(EntityReferenceResolver.TYPE_STRING, "relative");
}
return this.relativeEntityReferenceResolver;
}
private EntityReferenceSerializer<String> getLocalStringEntityReferenceSerializer()
{
if (this.localStringEntityReferenceSerializer == null) {
this.localStringEntityReferenceSerializer =
Utils.getComponent(EntityReferenceSerializer.TYPE_STRING, "local");
}
return this.localStringEntityReferenceSerializer;
}
private SyntaxFactory getSyntaxFactory()
{
if (this.syntaxFactory == null) {
this.syntaxFactory = Utils.getComponent(SyntaxFactory.class);
}
return this.syntaxFactory;
}
private ResourceReferenceManager getResourceReferenceManager()
{
if (this.resourceReferenceManager == null) {
this.resourceReferenceManager = Utils.getComponent(ResourceReferenceManager.class);
}
return this.resourceReferenceManager;
}
private JobExecutor getJobExecutor()
{
if (this.jobExecutor == null) {
this.jobExecutor = Utils.getComponent(JobExecutor.class);
}
return this.jobExecutor;
}
private DocumentReference getDefaultDocumentReference()
{
return getDefaultDocumentReferenceProvider().get();
}
private WikiSkinUtils getWikiSkinUtils()
{
if (this.wikiSkinUtils == null) {
this.wikiSkinUtils = Utils.getComponent(WikiSkinUtils.class);
}
return this.wikiSkinUtils;
}
private DocumentRevisionProvider getDocumentRevisionProvider()
{
if (this.documentRevisionProvider == null) {
this.documentRevisionProvider = Utils.getComponent(DocumentRevisionProvider.class);
}
return this.documentRevisionProvider;
}
private String localizePlainOrKey(String key, Object... parameters)
{
return StringUtils.defaultString(getLocalization().getTranslationPlain(key, parameters), key);
}
/**
* @param context see {@link XWikiContext}
*/
public static XWiki getMainXWiki(XWikiContext context) throws XWikiException
{
return getMainXWiki(true, context);
}
/**
* @param wait true if the method should way for {@link XWiki} instance to be initialized
* @param context see {@link XWikiContext}
*/
public static XWiki getMainXWiki(boolean wait, XWikiContext context) throws XWikiException
{
String xwikiname = DEFAULT_MAIN_WIKI;
context.setMainXWiki(xwikiname);
XWiki xwiki;
try {
XWikiEngineContext econtext = context.getEngineContext();
xwiki = (XWiki) econtext.getAttribute(xwikiname);
if (xwiki == null) {
// Start XWiki initialization
synchronized (XWiki.class) {
xwiki = (XWiki) econtext.getAttribute(xwikiname);
if (xwiki == null && job == null) {
job = Utils.getComponent((Type) Job.class, XWikiInitializerJob.JOBTYPE);
if (job.getStatus() == null) {
// "Pre-initialize" XWikiStubContextProvider so that XWiki initializer can find one
Utils.<XWikiStubContextProvider>getComponent(XWikiStubContextProvider.class)
.initialize(context);
job.startAsync();
}
}
}
// Wait until XWiki is initialized
if (wait) {
job.join();
xwiki = (XWiki) econtext.getAttribute(xwikiname);
}
}
context.setWiki(xwiki);
return xwiki;
} catch (Exception e) {
throw new XWikiException(XWikiException.MODULE_XWIKI, XWikiException.ERROR_XWIKI_INIT_FAILED,
"Could not initialize main XWiki instance", e);
}
}
public static boolean isInitializing(XWikiContext xcontext)
{
return Boolean.TRUE.equals(xcontext.getEngineContext().getAttribute("xwiki.init"));
}
/**
* Return the XWiki object (as in "the Wiki API") corresponding to the requested wiki.
*
* @param context see {@link XWikiContext}
* @return an XWiki object configured for the wiki corresponding to the current request
* @throws XWikiException if the requested URL does not correspond to a real wiki, or if there's an error in the
* storage
*/
public static XWiki getXWiki(XWikiContext context) throws XWikiException
{
return getXWiki(true, context);
}
/**
* Return the XWiki object (as in "the Wiki API") corresponding to the requested wiki.
* <p>
* Unless <code>wait</code> is false the method return right away null if XWiki is not yet initialized.
*
* @param wait wait until XWiki is initialized
* @param xcontext see {@link XWikiContext}
* @return an XWiki object configured for the wiki corresponding to the current request
* @throws XWikiException if the requested URL does not correspond to a real wiki, or if there's an error in the
* storage
*/
public static XWiki getXWiki(boolean wait, XWikiContext xcontext) throws XWikiException
{
XWiki xwiki = getMainXWiki(wait, xcontext);
if (xwiki == null) {
return null;
}
// Extract Entity Resource from URL and put it in the Execution Context
EntityResourceReference entityResourceReference = initializeResourceFromURL(xcontext);
// Get the wiki id
String wikiId = entityResourceReference.getEntityReference().extractReference(EntityType.WIKI).getName();
if (wikiId.equals(xcontext.getMainXWiki())) {
// The main wiki was requested.
return xwiki;
}
// Check if the wiki exists by checking if a descriptor exists for the wiki id.
WikiDescriptorManager wikiDescriptorManager = Utils.getComponent(WikiDescriptorManager.class);
WikiDescriptor descriptor;
try {
descriptor = wikiDescriptorManager.getById(wikiId);
} catch (WikiManagerException e) {
throw new XWikiException(XWikiException.MODULE_XWIKI, XWikiException.ERROR_XWIKI_STORE_MISC,
String.format("Failed find wiki descriptor for wiki id [%s]", wikiId), e);
}
if (descriptor == null) {
throw new XWikiException(XWikiException.MODULE_XWIKI, XWikiException.ERROR_XWIKI_DOES_NOT_EXIST,
String.format("The wiki [%s] does not exist", wikiId));
}
// Initialize wiki
xcontext.setWikiId(wikiId);
xcontext.setOriginalWikiId(wikiId);
if (!xwiki.initializeWiki(wikiId, wait, xcontext)) {
// The wiki is still initializing
return null;
}
return xwiki;
}
/**
* @param wikiId the identifier of the wiki
* @return the current {@link WikiInitializerJob} associated to the passed wiki or null if there is none
*/
public Job getWikiInitializerJob(String wikiId)
{
return this.initializedWikis.get(wikiId);
}
/**
* Make sure the wiki is initializing or wait for it.
*
* @param wikiId the identifier of the wiki to initialize
* @param wait true if the method should return only when the wiki is fully initialized
* @return true if the wiki is fully initialized
* @param xcontext the XWiki context
* @throws XWikiException when the initialization failed
* @since 8.4RC1
*/
public boolean initializeWiki(String wikiId, boolean wait, XWikiContext xcontext) throws XWikiException
{
Job wikiJob = this.initializedWikis.get(wikiId);
// Create and start the job if it does not exist
if (wikiJob == null) {
try {
wikiJob = initializeWiki(wikiId, xcontext);
} catch (JobException e) {
throw new XWikiException(XWikiException.MODULE_XWIKI, XWikiException.ERROR_XWIKI_INIT_FAILED,
"Could not start [" + wikiId + "] wiki initialization", e);
}
}
// Check if the job is done
if (wikiJob.getStatus().getState() == State.FINISHED) {
return true;
}
// Wait until the job is finished if asked to
if (wait) {
try {
wikiJob.join();
} catch (InterruptedException e) {
throw new XWikiException(XWikiException.MODULE_XWIKI, XWikiException.ERROR_XWIKI_INIT_FAILED,
"Wiki [" + wikiId + "] initialization was interrupted unexpectedly", e);
}
if (wikiJob.getStatus().getError() != null) {
throw new XWikiException(XWikiException.MODULE_XWIKI, XWikiException.ERROR_XWIKI_INIT_FAILED,
"Wiki [" + wikiId + "] initialization failed", wikiJob.getStatus().getError());
}
return true;
}
// Still initializing
return false;
}
private Job initializeWiki(String wikiId, XWikiContext xcontext) throws JobException
{
synchronized (this.initializedWikis) {
WikiInitializerJob wikiJob = this.initializedWikis.get(wikiId);
if (wikiJob == null) {
WikiInitializerRequest request = new WikiInitializerRequest(wikiId);
JobRequestContext.set(request, xcontext);
wikiJob = (WikiInitializerJob) getJobExecutor().execute(WikiInitializerJob.JOBTYPE, request);
this.initializedWikis.put(wikiId, wikiJob);
}
return wikiJob;
}
}
private static EntityResourceReference initializeResourceFromURL(XWikiContext context) throws XWikiException
{
// Extract the Entity Resource from the URL
// TODO: This code should be put in an ExecutionContextInitializer but we couldn't do yet since this code
// requires that the XWiki object be initialized first (the line above). Thus we'll be able to to move it only
// after the XWiki init is done also in an ExecutionContextInitializer (and with priorities).
@SuppressWarnings("deprecation")
EntityResourceReference entityResourceReference;
URL url = context.getURL();
try {
ExtendedURL extendedURL = new ExtendedURL(url, context.getRequest().getContextPath());
ResourceTypeResolver<ExtendedURL> typeResolver =
Utils.getComponent(new DefaultParameterizedType(null, ResourceTypeResolver.class, ExtendedURL.class));
ResourceType type = typeResolver.resolve(extendedURL, Collections.<String, Object>emptyMap());
ResourceReferenceResolver<ExtendedURL> resourceResolver = Utils
.getComponent(new DefaultParameterizedType(null, ResourceReferenceResolver.class, ExtendedURL.class));
entityResourceReference = (EntityResourceReference) resourceResolver.resolve(extendedURL, type,
Collections.<String, Object>emptyMap());
} catch (Exception e) {
throw new XWikiException(XWikiException.MODULE_XWIKI, XWikiException.ERROR_XWIKI_APP_URL_EXCEPTION,
String.format("Failed to extract Entity Resource Reference from URL [%s]", url), e);
}
Utils.getComponent(Execution.class).getContext().setProperty(ResourceReferenceManager.RESOURCE_CONTEXT_PROPERTY,
entityResourceReference);
return entityResourceReference;
}
public static URL getRequestURL(XWikiRequest request) throws XWikiException
{
try {
StringBuffer requestURL = request.getRequestURL();
String qs = request.getQueryString();
if ((qs != null) && (!qs.equals(""))) {
return new URL(requestURL.toString() + "?" + qs);
} else {
return new URL(requestURL.toString());
}
} catch (Exception e) {
throw new XWikiException(XWikiException.MODULE_XWIKI_APP, XWikiException.ERROR_XWIKI_APP_URL_EXCEPTION,
"Exception while getting URL from request", e);
}
}
public static Object callPrivateMethod(Object obj, String methodName)
{
return callPrivateMethod(obj, methodName, null, null);
}
public static Object callPrivateMethod(Object obj, String methodName, Class<?>[] classes, Object[] args)
{
try {
Method method = obj.getClass().getDeclaredMethod(methodName, classes);
method.setAccessible(true);
return method.invoke(obj, args);
} catch (IllegalAccessException e) {
LOGGER.error("Failed to call private method [{}]: [{}]", methodName, e);
return null;
} catch (NoSuchMethodException e) {
return null;
} catch (InvocationTargetException e) {
LOGGER.error("Private method [{}] failed: [{}]", methodName, e);
return null;
}
}
public static HttpClient getHttpClient(int timeout, String userAgent)
{
HttpClient client = new HttpClient();
if (timeout != 0) {
client.getParams().setSoTimeout(timeout);
client.getParams().setParameter("http.connection.timeout", Integer.valueOf(timeout));
}
client.getParams().setParameter("http.useragent", userAgent);
String proxyHost = System.getProperty("http.proxyHost");
String proxyPort = System.getProperty("http.proxyPort");
if ((proxyHost != null) && (!proxyHost.equals(""))) {
int port = 3128;
if ((proxyPort != null) && (!proxyPort.equals(""))) {
port = Integer.parseInt(proxyPort);
}
client.getHostConfiguration().setProxy(proxyHost, port);
}
String proxyUser = System.getProperty("http.proxyUser");
if ((proxyUser != null) && (!proxyUser.equals(""))) {
String proxyPassword = System.getProperty("http.proxyPassword");
Credentials defaultcreds = new UsernamePasswordCredentials(proxyUser, proxyPassword);
client.getState().setProxyCredentials(AuthScope.ANY, defaultcreds);
}
return client;
}
/**
* Using reflection, read the private value of the passed field name for the passed object.
*
* @param obj the java object on which to read the private field value
* @param fieldName the object member field for which to read the value
* @return the private value for the field
* @deprecated use {@link FieldUtils#readDeclaredField(Object, String, boolean)} instead
*/
@Deprecated
public static Object getPrivateField(Object obj, String fieldName)
{
try {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(obj);
} catch (NoSuchFieldException e) {
return null;
} catch (IllegalAccessException e) {
LOGGER.error("Failed to get private field with name [{}]: [{}]", fieldName, e);
return null;
} finally {
}
}
public static String getServerWikiPage(String servername)
{
return "XWiki.XWikiServer" + StringUtils.capitalize(servername);
}
/**
* @param content the content of the text area
* @param context see {@link XWikiContext}
*/
public static String getTextArea(String content, XWikiContext context)
{
StringBuilder result = new StringBuilder();
// Forcing a new line after the <textarea> tag, as
// http://www.w3.org/TR/html4/appendix/notes.html#h-B.3.1 causes an empty line at the start
// of the document content to be trimmed.
result.append("<textarea name=\"content\" id=\"content\" rows=\"25\" cols=\"80\">\n");
result.append(XMLUtils.escape(content));
result.append("</textarea>");
return result.toString();
}
/**
* This provide a way to create an XWiki object without initializing the whole XWiki (including plugins, storage,
* etc.).
* <p>
* Needed for tools or tests which need XWiki because it is used everywhere in the API.
*/
public XWiki()
{
// Empty voluntarily
}
/**
* Initialize all xwiki subsystems.
*
* @param context see {@link XWikiContext}
* @param engineContext the XWiki object wrapping the {@link javax.servlet.ServletContext} and which allows to set
* data that live on as long as the XWiki webapp is not stopped in the Servlet Container
* @param noupdate true if the whole initialization should be done (create mandatory xlcasses, initialize stats
* service), i.e. if this is not an update, and false otherwise
* @throws XWikiException if an error happened during initialization (failure to initialize some cache for example)
*/
public XWiki(XWikiContext context, XWikiEngineContext engineContext, boolean noupdate) throws XWikiException
{
initXWiki(context, engineContext, noupdate);
}
/**
* Initialize all xwiki subsystems.
*
* @param context see {@link XWikiContext}
* @throws XWikiException if an error happened during initialization (failure to initialize some cache for example)
*/
public XWiki(XWikiContext context) throws XWikiException
{
this(context, null, false);
}
/**
* Initialize all xwiki subsystems.
*
* @param context see {@link XWikiContext}
* @param engineContext the XWiki object wrapping the {@link javax.servlet.ServletContext} and which allows to set
* data that live on as long as the XWiki webapp is not stopped in the Servlet Container
* @param noupdate true if the whole initialization should be done (create mandatory xlcasses, initialize stats
* service), i.e. if this is not an update, and false otherwise
* @throws XWikiException if an error happened during initialization (failure to initialize some cache for example)
*/
public void initXWiki(XWikiContext context, XWikiEngineContext engineContext, boolean noupdate)
throws XWikiException
{
initXWiki(null, context, engineContext, noupdate);
}
/**
* Initialize all xwiki subsystems.
*
* @param config the object holding the XWiki configuration read from {@code xwiki.cfg}
* @param context see {@link XWikiContext}
* @param engineContext the XWiki object wrapping the {@link javax.servlet.ServletContext} and which allows to set
* data that live on as long as the XWiki webapp is not stopped in the Servlet Container
* @param noupdate true if the whole initialization should be done (create mandatory xlcasses, initialize stats
* service), i.e. if this is not an update, and false otherwise
* @throws XWikiException if an error happened during initialization (failure to initialize some cache for example)
* @deprecated since 6.1M2, use {@link #initXWiki(XWikiContext, XWikiEngineContext, boolean)} instead
*/
@Deprecated
public void initXWiki(XWikiConfig config, XWikiContext context, XWikiEngineContext engineContext, boolean noupdate)
throws XWikiException
{
getProgress().pushLevelProgress(4, this);
try {
getProgress().startStep(this);
setDatabase(context.getMainXWiki());
setEngineContext(engineContext);
context.setWiki(this);
// "Pre-initialize" XWikiStubContextProvider with a XWikiContext containing a XWiki instance as soon as
// possible
Utils.<XWikiStubContextProvider>getComponent(XWikiStubContextProvider.class).initialize(context);
// Prepare the store
if (config != null) {
setConfig(config);
}
XWikiStoreInterface mainStore = Utils.getComponent(XWikiStoreInterface.class,
getConfiguration().getProperty("xwiki.store.main.hint", "hibernate"));
// Check if we need to use the cache store..
boolean nocache = "0".equals(getConfiguration().getProperty("xwiki.store.cache", "1"));
if (!nocache) {
XWikiCacheStoreInterface cachestore = new XWikiCacheStore(mainStore, context);
setStore(cachestore);
} else {
setStore(mainStore);
}
setCriteriaService((XWikiCriteriaService) createClassFromConfig("xwiki.criteria.class",
"com.xpn.xwiki.criteria.impl.XWikiCriteriaServiceImpl", context));
setAttachmentStore(Utils.<XWikiAttachmentStoreInterface>getComponent(XWikiAttachmentStoreInterface.class,
getConfiguration().getProperty("xwiki.store.attachment.hint", "hibernate")));
setVersioningStore(Utils.<XWikiVersioningStoreInterface>getComponent(XWikiVersioningStoreInterface.class,
getConfiguration().getProperty("xwiki.store.versioning.hint", "hibernate")));
setAttachmentVersioningStore(Utils.<AttachmentVersioningStore>getComponent(AttachmentVersioningStore.class,
hasAttachmentVersioning(context)
? getConfiguration().getProperty("xwiki.store.attachment.versioning.hint", "hibernate") : "void"));
if (hasRecycleBin(context)) {
setRecycleBinStore(
Utils.<XWikiRecycleBinStoreInterface>getComponent(XWikiRecycleBinStoreInterface.class,
getConfiguration().getProperty("xwiki.store.recyclebin.hint", "hibernate")));
}
if (hasAttachmentRecycleBin(context)) {
setAttachmentRecycleBinStore(
Utils.<AttachmentRecycleBinStore>getComponent(AttachmentRecycleBinStore.class,
getConfiguration().getProperty("xwiki.store.attachment.recyclebin.hint", "hibernate")));
}
// "Pre-initialize" XWikiStubContextProvider so that rendering engine, plugins or listeners reacting to
// potential document changes can use it
Utils.<XWikiStubContextProvider>getComponent(XWikiStubContextProvider.class).initialize(context);
getProgress().endStep(this);
getProgress().startStep(this);
// Make sure these classes exists
if (noupdate) {
initializeMandatoryDocuments(context);
getStatsService(context);
}
getProgress().endStep(this);
getProgress().startStep(this);
// Prepare the Plugin Engine
preparePlugins(context);
getProgress().endStep(this);
getProgress().startStep(this);
String ro = getConfiguration().getProperty("xwiki.readonly", "no");
this.isReadOnly = ("yes".equalsIgnoreCase(ro) || "true".equalsIgnoreCase(ro) || "1".equalsIgnoreCase(ro));
// Save the configured syntaxes
String syntaxes = getConfiguration().getProperty("xwiki.rendering.syntaxes", "xwiki/1.0");
this.configuredSyntaxes = Arrays.asList(StringUtils.split(syntaxes, " ,"));
getObservationManager().addListener(this);
} finally {
getProgress().popLevelProgress(this);
}
}
/**
* Ensure that mandatory classes (ie classes XWiki needs to work properly) exist and create them if they don't
* exist.
*
* @param context see {@link XWikiContext}
*/
public void initializeMandatoryDocuments(XWikiContext context)
{
if (context.get("initdone") == null) {
@SuppressWarnings("deprecation")
List<MandatoryDocumentInitializer> initializers =
Utils.getComponentList(MandatoryDocumentInitializer.class);
// Sort the initializers based on priority. Lower priority values are first.
Collections.sort(initializers, new Comparator<MandatoryDocumentInitializer>()
{
@Override
public int compare(MandatoryDocumentInitializer left, MandatoryDocumentInitializer right)
{
Priority leftPriority = left.getClass().getAnnotation(Priority.class);
int leftPriorityValue =
leftPriority != null ? leftPriority.value() : MandatoryDocumentInitializer.DEFAULT_PRIORITY;
Priority rightPriority = right.getClass().getAnnotation(Priority.class);
int rightPriorityValue =
rightPriority != null ? rightPriority.value() : MandatoryDocumentInitializer.DEFAULT_PRIORITY;
// Compare the two.
return leftPriorityValue - rightPriorityValue;
}
});
for (MandatoryDocumentInitializer initializer : initializers) {
initializeMandatoryDocument(initializer, context);
}
}
}
private void initializeMandatoryDocument(String wiki, MandatoryDocumentInitializer initializer,
XWikiContext context)
{
String currentWiki = context.getWikiId();
try {
context.setWikiId(wiki);
initializeMandatoryDocument(initializer, context);
} finally {
context.setWikiId(currentWiki);
}
}
private void initializeMandatoryDocument(MandatoryDocumentInitializer initializer, XWikiContext context)
{
try {
DocumentReference documentReference =
getCurrentReferenceDocumentReferenceResolver().resolve(initializer.getDocumentReference());
if (documentReference.getWikiReference().getName().equals(context.getWikiId())) {
XWikiDocument document = context.getWiki().getDocument(documentReference, context);
if (initializer.updateDocument(document)) {
saveDocument(document,
localizePlainOrKey("core.model.xclass.mandatoryUpdateProperty.versionSummary"), context);
}
}
} catch (XWikiException e) {
LOGGER.error("Failed to initialize mandatory document", e);
}
}
public XWikiStoreInterface getNotCacheStore()
{
XWikiStoreInterface store = getStore();
if (store instanceof XWikiCacheStoreInterface) {
store = ((XWikiCacheStoreInterface) store).getStore();
}
return store;
}
public XWikiHibernateStore getHibernateStore()
{
XWikiStoreInterface store = getStore();
if (store instanceof XWikiHibernateStore) {
return (XWikiHibernateStore) store;
} else if (store instanceof XWikiCacheStoreInterface) {
store = ((XWikiCacheStoreInterface) store).getStore();
if (store instanceof XWikiHibernateStore) {
return (XWikiHibernateStore) store;
} else {
return null;
}
} else {
return null;
}
}
/**
* @param wikiId the id of the wiki
* @param context see {@link XWikiContext}
* @deprecated since 8.4RC1, use {@link #initializeWiki(String, boolean, XWikiContext)} instead
*/
@Deprecated
public void updateDatabase(String wikiId, XWikiContext context) throws HibernateException, XWikiException
{
updateDatabase(wikiId, false, context);
}
/**
* @param wikiId the id of the wiki
* @param context see {@link XWikiContext}
* @deprecated since 8.4RC1, use {@link #initializeWiki(String, boolean, XWikiContext)} instead
*/
@Deprecated
public void updateDatabase(String wikiId, boolean force, XWikiContext context)
throws HibernateException, XWikiException
{
updateDatabase(wikiId, force, true, context);
}
/**
* @param wikiId the id of the wiki
* @param force if the update of the databse should be forced
* @param initDocuments if mandatory document and plugin should be initialized for passed wiki
* @param context see {@link XWikiContext}
* @deprecated since 8.4RC1, use {@link #initializeWiki(String, boolean, XWikiContext)} instead
*/
@Deprecated
public void updateDatabase(String wikiId, boolean force, boolean initDocuments, XWikiContext context)
throws HibernateException, XWikiException
{
initializeWiki(wikiId, true, context);
}
/**
* @return a cached list of all active virtual wikis (i.e. wikis who have been hit by a user request). To get a full
* list of all virtual wikis database names use {@link WikiDescriptorManager#getAllIds()}.
*/
@Deprecated
public List<String> getVirtualWikiList()
{
return new ArrayList<>(this.initializedWikis.keySet());
}
/**
* @param context see {@link XWikiContext}
* @return the full list of all wiki names of all defined wikis. The wiki names are computed from the names of
* documents having a {@code XWiki.XWikiServerClass} object attached to them by removing the
* {@code XWiki.XWikiServer} prefix and making it lower case. For example a page named
* {@code XWiki.XWikiServerMyDatabase} would return {@code mydatabase} as the wiki name. This list will also
* contain the main wiki.
* <p>
* Note: the wiki name is commonly also the name of the database where the wiki's data is stored. However,
* if configured accordingly, the database can be diferent from the wiki name, like for example when setting
* a wiki database prefix.
* @deprecated since 5.3, use {@link WikiDescriptorManager#getAllIds()} instead
*/
@Deprecated
public List<String> getVirtualWikisDatabaseNames(XWikiContext context) throws XWikiException
{
WikiDescriptorManager descriptorManager = Utils.getComponent(WikiDescriptorManager.class);
try {
return new ArrayList<String>(descriptorManager.getAllIds());
} catch (WikiManagerException e) {
throw new XWikiException(XWikiException.MODULE_XWIKI, XWikiException.ERROR_XWIKI_UNKNOWN,
"Failed to get the list of wikis", e);
}
}
/**
* @return the cache containing the names of the wikis already initialized.
* @since 1.5M2.
*/
@Deprecated
public Cache<DocumentReference> getVirtualWikiCache()
{
return null;
}
/**
* Get the reference of the owner for the provider wiki.
*
* @param wikiName the technical name of the wiki
* @param context see {@link XWikiContext}
* @return the wiki owner or null if none is set
* @throws XWikiException failed to get wiki descriptor document
*/
public String getWikiOwner(String wikiName, XWikiContext context) throws XWikiException
{
String wikiOwner;
String currentdatabase = context.getWikiId();
try {
context.setWikiId(context.getMainXWiki());
String serverwikipage = getServerWikiPage(wikiName);
XWikiDocument doc = getDocument(serverwikipage, context);
if (doc.isNew()) {
if (!context.isMainWiki(wikiName)) {
throw new XWikiException(XWikiException.MODULE_XWIKI, XWikiException.ERROR_XWIKI_DOES_NOT_EXIST,
"The wiki " + wikiName + " does not exist");
} else {
wikiOwner = null;
}
} else {
wikiOwner = doc.getStringValue(VIRTUAL_WIKI_DEFINITION_CLASS_REFERENCE, "owner");
if (wikiOwner.indexOf(':') == -1) {
wikiOwner = context.getMainXWiki() + ":" + wikiOwner;
}
}
} finally {
context.setWikiId(currentdatabase);
}
return wikiOwner;
}
/**
* @param context see {@link XWikiContext}
*/
protected Object createClassFromConfig(String param, String defClass, XWikiContext context) throws XWikiException
{
String storeclass = getConfiguration().getProperty(param, defClass);
try {
Class<?>[] classes = new Class<?>[] { XWikiContext.class };
Object[] args = new Object[] { context };
Object result = Class.forName(storeclass).getConstructor(classes).newInstance(args);
return result;
} catch (Exception e) {
Throwable ecause = e;
if (e instanceof InvocationTargetException) {
ecause = ((InvocationTargetException) e).getTargetException();
}
Object[] args = { param, storeclass };
throw new XWikiException(XWikiException.MODULE_XWIKI_STORE,
XWikiException.ERROR_XWIKI_STORE_CLASSINVOCATIONERROR, "Cannot load class {1} from param {0}", ecause,
args);
}
}
private void preparePlugins(XWikiContext context)
{
setPluginManager(new XWikiPluginManager(getXWikiPreference("plugins", context), context));
String plugins = getConfiguration().getProperty("xwiki.plugins", "");
if (!plugins.equals("")) {
getPluginManager().addPlugins(StringUtils.split(plugins, " ,"), context);
}
}
/**
* @return the XWiki core version as specified in the {@link #VERSION_FILE} file
*/
@SuppressWarnings("deprecation")
public String getVersion()
{
if (this.version == null) {
try {
InputStream is = getResourceAsStream(VERSION_FILE);
try {
XWikiConfig properties = new XWikiConfig(is);
this.version = properties.getProperty(VERSION_FILE_PROPERTY);
} finally {
IOUtils.closeQuietly(is);
}
} catch (Exception e) {
// Failed to retrieve the version, log a warning and default to "Unknown"
LOGGER.warn("Failed to retrieve XWiki's version from [" + VERSION_FILE + "], using the ["
+ VERSION_FILE_PROPERTY + "] property.", e);
this.version = "Unknown version";
}
}
return this.version;
}
public URL getResource(String s) throws MalformedURLException
{
return getEngineContext().getResource(s);
}
public InputStream getResourceAsStream(String s) throws MalformedURLException
{
InputStream is = getEngineContext().getResourceAsStream(s);
if (is == null) {
is = getEngineContext().getResourceAsStream("/" + s);
}
return is;
}
public String getResourceContent(String name) throws IOException
{
InputStream is = null;
if (getEngineContext() != null) {
try {
is = getResourceAsStream(name);
} catch (Exception e) {
}
}
if (is == null) {
// Resources should always be encoded as UTF-8, to reduce the dependency on the system encoding
return FileUtils.readFileToString(new File(name), DEFAULT_ENCODING);
}
try {
return IOUtils.toString(is, DEFAULT_ENCODING);
} finally {
IOUtils.closeQuietly(is);
}
}
public Date getResourceLastModificationDate(String name)
{
try {
if (getEngineContext() != null) {
return Util.getFileLastModificationDate(getEngineContext().getRealPath(name));
}
} catch (Exception ex) {
// Probably a SecurityException or the file is not accessible (inside a war)
LOGGER.info("Failed to get file modification date: " + ex.getMessage());
}
return new Date();
}
public byte[] getResourceContentAsBytes(String name) throws IOException
{
InputStream is = null;
if (getEngineContext() != null) {
try {
is = getResourceAsStream(name);
} catch (Exception e) {
}
}
if (is == null) {
return FileUtils.readFileToByteArray(new File(name));
}
try {
return IOUtils.toByteArray(is);
} finally {
IOUtils.closeQuietly(is);
}
}
public boolean resourceExists(String name)
{
if (getEngineContext() != null) {
try {
if (getResource(name) != null) {
return true;
}
} catch (IOException e) {
}
}
try {
File file = new File(name);
return file.exists();
} catch (Exception e) {
// Could be running under -security, which prevents calling file.exists().
}
return false;
}
public String getRealPath(String path)
{
return getEngineContext().getRealPath(path);
}
public String ParamAsRealPath(String key)
{
String param = getConfiguration().getProperty(key);
try {
return getRealPath(param);
} catch (Exception e) {
return param;
}
}
/**
* @param context see {@link XWikiContext}
*/
public String ParamAsRealPath(String key, XWikiContext context)
{
return ParamAsRealPath(key);
}
public String ParamAsRealPathVerified(String param)
{
String path;
File fpath;
path = getConfiguration().getProperty(param);
if (path == null) {
return null;
}
fpath = new File(path);
if (fpath.exists()) {
return path;
}
path = getRealPath(path);
if (path == null) {
return null;
}
fpath = new File(path);
if (fpath.exists()) {
return path;
} else {
}
return null;
}
public XWikiStoreInterface getStore()
{
return this.store;
}
public XWikiAttachmentStoreInterface getAttachmentStore()
{
return this.attachmentStore;
}
public AttachmentVersioningStore getAttachmentVersioningStore()
{
return this.attachmentVersioningStore;
}
public XWikiVersioningStoreInterface getVersioningStore()
{
return this.versioningStore;
}
public XWikiRecycleBinStoreInterface getRecycleBinStore()
{
return this.recycleBinStore;
}
public AttachmentRecycleBinStore getAttachmentRecycleBinStore()
{
return this.attachmentRecycleBinStore;
}
/**
* @param doc the document to save
* @param context see {@link XWikiContext}
*/
public void saveDocument(XWikiDocument doc, XWikiContext context) throws XWikiException
{
// If no comment is provided we should use an empty comment
saveDocument(doc, "", context);
}
/**
* @param doc the document to save
* @param comment the comment to associated to the new version of the saved document
* @param context see {@link XWikiContext}
*/
public void saveDocument(XWikiDocument doc, String comment, XWikiContext context) throws XWikiException
{
saveDocument(doc, comment, false, context);
}
/**
* @param document the document to save
* @param comment the comment to associated to the new version of the saved document
* @param isMinorEdit true if the new version is a minor version
* @param context see {@link XWikiContext}
*/
public void saveDocument(XWikiDocument document, String comment, boolean isMinorEdit, XWikiContext context)
throws XWikiException
{
String currentWiki = context.getWikiId();
try {
// Switch to document wiki
context.setWikiId(document.getDocumentReference().getWikiReference().getName());
// Setting comment & minor edit before saving
document.setComment(StringUtils.defaultString(comment));
document.setMinorEdit(isMinorEdit);
// We need to save the original document since saveXWikiDoc() will reset it and we
// need that original document for the notification below.
XWikiDocument originalDocument = document.getOriginalDocument();
// Make sure to always have an original document for listeners that need to compare with it.
// The only case where we have a null original document is supposedly when the document
// instance has been crafted and passed #saveDocument without using #getDocument
// (which is not a good practice)
if (originalDocument == null) {
originalDocument =
getDocument(new DocumentReference(document.getDocumentReference(), document.getLocale()), context);
document.setOriginalDocument(originalDocument);
}
ObservationManager om = getObservationManager();
// Notify listeners about the document about to be created or updated
// Note that for the moment the event being send is a bridge event, as we are still passing around
// an XWikiDocument as source and an XWikiContext as data.
if (om != null) {
CancelableEvent documentEvent;
if (originalDocument.isNew()) {
documentEvent = new DocumentCreatingEvent(document.getDocumentReference());
} else {
documentEvent = new DocumentUpdatingEvent(document.getDocumentReference());
}
om.notify(documentEvent, document, context);
// If the action has been canceled by the user then don't perform any save and throw an exception
if (documentEvent.isCanceled()) {
throw new XWikiException(XWikiException.MODULE_XWIKI_STORE,
XWikiException.ERROR_XWIKI_STORE_HIBERNATE_SAVING_DOC,
String.format("An Event Listener has cancelled the document save for [%s]. Reason: [%s]",
document.getDocumentReference(), documentEvent.getReason()));
}
}
// Put attachments to remove in recycle bin
if (hasAttachmentRecycleBin(context)) {
for (XWikiAttachmentToRemove attachment : document.getAttachmentsToRemove()) {
if (attachment.isToRecycleBin()) {
getAttachmentRecycleBinStore().saveToRecycleBin(attachment.getAttachment(), context.getUser(),
new Date(), context, true);
}
}
}
// Actually save the document.
getStore().saveXWikiDoc(document, context);
// Since the store#saveXWikiDoc resets originalDocument, we need to temporarily put it
// back to send notifications.
XWikiDocument newOriginal = document.getOriginalDocument();
try {
document.setOriginalDocument(originalDocument);
// Notify listeners about the document having been created or updated
// First the legacy notification mechanism
// Then the new observation module
// Note that for the moment the event being send is a bridge event, as we are still passing around
// an XWikiDocument as source and an XWikiContext as data.
// The old version is made available using doc.getOriginalDocument()
if (om != null) {
if (originalDocument.isNew()) {
om.notify(new DocumentCreatedEvent(document.getDocumentReference()), document, context);
} else {
om.notify(new DocumentUpdatedEvent(document.getDocumentReference()), document, context);
}
}
} catch (Exception ex) {
LOGGER.error("Failed to send document save notification for document ["
+ getDefaultEntityReferenceSerializer().serialize(document.getDocumentReference()) + "]", ex);
} finally {
document.setOriginalDocument(newOriginal);
}
} finally {
context.setWikiId(currentWiki);
}
}
/**
* Loads a XWikiDocument from the store.
* <p>
* Before 7.2M1 the reference is assumed to be a complete or incomplete document reference.
* <p>
* Since 7.2M1, the passed reference can be anything. If if a document child, the document reference will be
* extracted from it. If it's a document parent it will be completed with the necessary default references (for
* example if it's a space reference it will load the space home page).
*
* @param reference the reference of teh document
* @param context see {@link XWikiContext}
* @since 5.0M1
*/
public XWikiDocument getDocument(EntityReference reference, XWikiContext context) throws XWikiException
{
return getDocument(getCurrentGetDocumentResolver().resolve(reference), context);
}
/**
* @param doc the document
* @param context see {@link XWikiContext}
*/
public XWikiDocument getDocument(XWikiDocument doc, XWikiContext context) throws XWikiException
{
String currentWiki = context.getWikiId();
try {
context.setWikiId(doc.getDocumentReference().getWikiReference().getName());
return getStore().loadXWikiDoc(doc, context);
} finally {
context.setWikiId(currentWiki);
}
}
/**
* @param reference the reference of the document
* @param revision the version of the document
* @since 9.3RC1
*/
public XWikiDocument getDocument(DocumentReference reference, String revision, XWikiContext context)
throws XWikiException
{
return getDocumentRevisionProvider().getRevision(reference, revision);
}
/**
* @param doc the document
* @param revision the version of the document
* @param context see {@link XWikiContext}
*/
public XWikiDocument getDocument(XWikiDocument doc, String revision, XWikiContext context) throws XWikiException
{
return getDocumentRevisionProvider().getRevision(doc, revision);
}
/**
* @param reference the reference of the document
* @param context see {@link XWikiContext}
* @since 2.2M1
*/
public XWikiDocument getDocument(DocumentReference reference, XWikiContext context) throws XWikiException
{
XWikiDocument doc = new XWikiDocument(
reference.getLocale() != null ? new DocumentReference(reference, null) : reference, reference.getLocale());
doc.setContentDirty(true);
return getDocument(doc, context);
}
/**
* @param fullname the reference of the document as String
* @param context see {@link XWikiContext}
* @deprecated since 2.2M1 use {@link #getDocument(DocumentReference, XWikiContext)} instead
*/
@Deprecated
public XWikiDocument getDocument(String fullname, XWikiContext context) throws XWikiException
{
XWikiDocument doc = new XWikiDocument();
doc.setFullName(fullname, context);
return getDocument(doc, context);
}
/**
* @param spaces the reference of the space as String
* @param fullname the reference of the document as String
* @param context see {@link XWikiContext}
* @deprecated since 2.2M1 use {@link #getDocument(DocumentReference, XWikiContext)} instead
*/
@Deprecated
public XWikiDocument getDocument(String spaces, String fullname, XWikiContext context) throws XWikiException
{
int dotPosition = fullname.lastIndexOf('.');
if (dotPosition != -1) {
String spaceFromFullname = fullname.substring(0, dotPosition);
String name = fullname.substring(dotPosition + 1);
if (name.equals("")) {
name = getDefaultPage(context);
}
return getDocument(spaceFromFullname + "." + name, context);
} else {
return getDocument(spaces + "." + fullname, context);
}
}
/**
* @see com.xpn.xwiki.api.XWiki#getDeletedDocuments(String, String)
*/
public XWikiDeletedDocument[] getDeletedDocuments(String fullname, String locale, XWikiContext context)
throws XWikiException
{
if (hasRecycleBin(context)) {
XWikiDocument doc = new XWikiDocument(getCurrentMixedDocumentReferenceResolver().resolve(fullname));
doc.setLanguage(locale);
return getRecycleBinStore().getAllDeletedDocuments(doc, context, true);
} else {
return null;
}
}
/**
* @see com.xpn.xwiki.api.XWiki#getDeletedDocuments(String)
* @since 9.4RC1
*/
public XWikiDeletedDocument[] getDeletedDocuments(String batchId, XWikiContext context) throws XWikiException
{
if (hasRecycleBin(context)) {
return getRecycleBinStore().getAllDeletedDocuments(batchId, context, true);
} else {
return null;
}
}
/**
* @see com.xpn.xwiki.api.XWiki#getDeletedDocument(String, String, String)
* @deprecated since 9.4RC1. Use {@link #getDeletedDocument(long, XWikiContext)} instead.
*/
@Deprecated
public XWikiDeletedDocument getDeletedDocument(String fullname, String locale, int index, XWikiContext context)
throws XWikiException
{
return getDeletedDocument(index, context);
}
/**
* @see com.xpn.xwiki.api.XWiki#getDeletedDocument(String)
* @since 9.4RC1
*/
public XWikiDeletedDocument getDeletedDocument(long index, XWikiContext context) throws XWikiException
{
if (hasRecycleBin(context)) {
return getRecycleBinStore().getDeletedDocument(index, context, true);
} else {
return null;
}
}
/**
* Retrieve all the deleted attachments that belonged to a certain document. Note that this does not distinguish
* between different incarnations of a document name, and it does not require that the document still exists, it
* returns all the attachments that at the time of their deletion had a document with the specified name as their
* owner.
*
* @param docName the {@link XWikiDocument#getFullName() name} of the owner document
* @param context see {@link XWikiContext}
* @return A list with all the deleted attachments which belonged to the specified document. If no such attachments
* are found in the trash, an empty list is returned.
* @throws XWikiException if an error occurs while loading the attachments
*/
public List<DeletedAttachment> getDeletedAttachments(String docName, XWikiContext context) throws XWikiException
{
if (hasAttachmentRecycleBin(context)) {
XWikiDocument doc = new XWikiDocument(getCurrentMixedDocumentReferenceResolver().resolve(docName));
return getAttachmentRecycleBinStore().getAllDeletedAttachments(doc, context, true);
}
return null;
}
/**
* Retrieve all the deleted attachments that belonged to a certain document and had the specified name. Multiple
* versions can be returned since the same file can be uploaded and deleted several times, creating different
* instances in the trash. Note that this does not distinguish between different incarnations of a document name,
* and it does not require that the document still exists, it returns all the attachments that at the time of their
* deletion had a document with the specified name as their owner.
*
* @param docName the {@link DeletedAttachment#getDocName() name of the document} the attachment belonged to
* @param filename the {@link DeletedAttachment#getFilename() name} of the attachment to search for
* @param context see {@link XWikiContext}
* @return A list with all the deleted attachments which belonged to the specified document and had the specified
* filename. If no such attachments are found in the trash, an empty list is returned.
* @throws XWikiException if an error occurs while loading the attachments
*/
public List<DeletedAttachment> getDeletedAttachments(String docName, String filename, XWikiContext context)
throws XWikiException
{
if (hasAttachmentRecycleBin(context)) {
XWikiDocument doc = new XWikiDocument(getCurrentMixedDocumentReferenceResolver().resolve(docName));
XWikiAttachment attachment = new XWikiAttachment(doc, filename);
return getAttachmentRecycleBinStore().getAllDeletedAttachments(attachment, context, true);
}
return null;
}
/**
* Retrieve a specific attachment from the trash.
*
* @param id the unique identifier of the entry in the trash
* @param context the XWiki context
* @return specified attachment from the trash, {@code null} if not found
* @throws XWikiException if an error occurs while loading the attachments
*/
public DeletedAttachment getDeletedAttachment(String id, XWikiContext context) throws XWikiException
{
if (hasAttachmentRecycleBin(context)) {
return getAttachmentRecycleBinStore().getDeletedAttachment(NumberUtils.toLong(id), context, true);
}
return null;
}
public MetaClass getMetaclass()
{
if (this.metaclass == null) {
this.metaclass = MetaClass.getMetaClass();
}
return this.metaclass;
}
public void setMetaclass(MetaClass metaclass)
{
this.metaclass = metaclass;
}
/**
* @param context see {@link XWikiContext}
*/
public List<String> getClassList(XWikiContext context) throws XWikiException
{
List<String> result = getStore().getClassList(context);
Collections.sort(result);
return result;
}
/**
* @param sql the sql query to execute
* @param context see {@link XWikiContext}
*/
public <T> List<T> search(String sql, XWikiContext context) throws XWikiException
{
return getStore().search(sql, 0, 0, context);
}
/**
* @param sql the sql query to execute
* @param nb limit the number of results to return
* @param start the offset from which to start return results
* @param context see {@link XWikiContext}
*/
public <T> List<T> search(String sql, int nb, int start, XWikiContext context) throws XWikiException
{
return getStore().search(sql, nb, start, context);
}
/**
* @param sql the sql query to execute
* @param context see {@link XWikiContext}
*/
public <T> List<T> search(String sql, Object[][] whereParams, XWikiContext context) throws XWikiException
{
return getStore().search(sql, 0, 0, whereParams, context);
}
/**
* @param sql the sql query to execute
* @param nb limit the number of results to return
* @param start the offset from which to start return results
* @param context see {@link XWikiContext}
*/
public <T> List<T> search(String sql, int nb, int start, Object[][] whereParams, XWikiContext context)
throws XWikiException
{
return getStore().search(sql, nb, start, whereParams, context);
}
/**
* @param content the content to parse
* @param context see {@link XWikiContext}
* @deprecated Since 7.2M1. Use specific rendering/parsing options for the content type you want to parse/render.
*/
@Deprecated
public String parseContent(String content, XWikiContext context)
{
return getOldRendering().parseContent(content, context);
}
/**
* @param template the name of the template
* @param context see {@link XWikiContext}
* @deprecated use {@link #evaluateTemplate(String, XWikiContext)} instead
*/
@Deprecated
public String parseTemplate(String template, XWikiContext context)
{
String result = "";
try {
result = evaluateTemplate(template, context);
} catch (Exception e) {
LOGGER.debug("Exception while parsing template [{}] from /templates/", template, e);
}
return result;
}
/**
* Evaluate provided template content using velocity engine.
*
* @param template the template to evaluate
* @param context see {@link XWikiContext}
* @return the return of the velocity script
* @throws IOException failed to get the template content
* @since 2.2.2
* @deprecated since 7.0M1, use {@link TemplateManager#render(String)} instead
*/
@Deprecated
public String evaluateTemplate(String template, XWikiContext context) throws IOException
{
try {
return getTemplateManager().render(template);
} catch (Exception e) {
LOGGER.error("Error while evaluating velocity template [{}]", template, e);
Object[] args = { template };
XWikiException xe = new XWikiException(XWikiException.MODULE_XWIKI_RENDERING,
XWikiException.ERROR_XWIKI_RENDERING_VELOCITY_EXCEPTION, "Error while evaluating velocity template {0}",
e, args);
return Util.getHTMLExceptionMessage(xe, context);
}
}
/**
* @param template the name of the template
* @param skinId the id of the skin from which to load the template
* @param context see {@link XWikiContext}
* @deprecated since 7.0M1, use {@link TemplateManager#renderFromSkin(String, Skin)} instead
*/
@Deprecated
public String parseTemplate(String template, String skinId, XWikiContext context)
{
MutableRenderingContext mutableRenderingContext = getMutableRenderingContext();
Syntax currentTargetSyntax = mutableRenderingContext.getTargetSyntax();
try {
// Force rendering with XHTML 1.0 syntax for retro-compatibility
mutableRenderingContext.setTargetSyntax(Syntax.XHTML_1_0);
Skin skin = getInternalSkinManager().getSkin(skinId);
return getTemplateManager().renderFromSkin(template, skin);
} catch (Exception e) {
LOGGER.error("Error while evaluating velocity template [{}] skin [{}]", template, skinId, e);
Object[] args = { template, skinId };
XWikiException xe = new XWikiException(XWikiException.MODULE_XWIKI_RENDERING,
XWikiException.ERROR_XWIKI_RENDERING_VELOCITY_EXCEPTION,
"Error while evaluating velocity template [{0}] from skin [{1}]", e, args);
return Util.getHTMLExceptionMessage(xe, context);
} finally {
mutableRenderingContext.setTargetSyntax(currentTargetSyntax);
}
}
/**
* @param template the name of the template
* @param skin the id of the skin from which to load the template
* @param context see {@link XWikiContext}
*/
public String renderTemplate(String template, String skin, XWikiContext context)
{
try {
return getOldRendering().renderTemplate(template, skin, context);
} catch (Exception ex) {
LOGGER.error("Failed to render template [" + template + "] for skin [" + skin + "]", ex);
return parseTemplate(template, skin, context);
}
}
/**
* @param template the name of the template
* @param context see {@link XWikiContext}
*/
public String renderTemplate(String template, XWikiContext context)
{
try {
return getOldRendering().renderTemplate(template, context);
} catch (Exception ex) {
LOGGER.error("Failed to render template [" + template + "]", ex);
return parseTemplate(template, context);
}
}
/**
* Designed to include dynamic content, such as Servlets or JSPs, inside Velocity templates; works by creating a
* RequestDispatcher, buffering the output, then returning it as a string.
*/
public String invokeServletAndReturnAsString(String url, XWikiContext xwikiContext)
{
HttpServletRequest servletRequest = xwikiContext.getRequest();
HttpServletResponse servletResponse = xwikiContext.getResponse();
try {
return IncludeServletAsString.invokeServletAndReturnAsString(url, servletRequest, servletResponse);
} catch (Exception e) {
LOGGER.warn("Exception including url: " + url, e);
return "Exception including \"" + url + "\", see logs for details.";
}
}
/**
* @param iconName the standard name of an icon (it's not the name of the file on the filesystem, it's a generic
* name, for example "success" for a success icon
* @param context see {@link XWikiContext}
* @return the URL to the icon resource
* @since 2.6M1
*/
public String getIconURL(String iconName, XWikiContext context)
{
// TODO: Do a better mapping between generic icon name and physical resource name, especially to be independent
// of the underlying icon library. Right now we assume it's the Silk icon library.
return getSkinFile("icons/silk/" + iconName + ".png", context);
}
public String getSkinFile(String filename, XWikiContext context)
{
return getSkinFile(filename, false, context);
}
public String getSkinFile(String filename, boolean forceSkinAction, XWikiContext context)
{
XWikiURLFactory urlf = context.getURLFactory();
try {
// Try in the specified skin
Skin skin = getInternalSkinManager().getCurrentSkin(true);
if (skin != null) {
Resource<?> resource = skin.getResource(filename);
if (resource != null) {
return resource.getURL(forceSkinAction);
}
} else {
// Try in the current parent skin
Skin parentSkin = getInternalSkinManager().getCurrentParentSkin(true);
if (parentSkin != null) {
Resource<?> resource = parentSkin.getResource(filename);
if (resource != null) {
return resource.getURL(forceSkinAction);
}
}
}
// Look for a resource file
if (resourceExists("/resources/" + filename)) {
URL url = urlf.createResourceURL(filename, forceSkinAction, context);
return urlf.getURL(url, context);
}
} catch (Exception e) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Exception while getting skin file [" + filename + "]", e);
}
}
// If all else fails, use the default base skin, even if the URLs could be invalid.
URL url;
if (forceSkinAction) {
url = urlf.createSkinURL(filename, "skins", getDefaultBaseSkin(context), context);
} else {
url = urlf.createSkinURL(filename, getDefaultBaseSkin(context), context);
}
return urlf.getURL(url, context);
}
public String getSkinFile(String filename, String skin, XWikiContext context)
{
return getSkinFile(filename, skin, false, context);
}
public String getSkinFile(String filename, String skinId, boolean forceSkinAction, XWikiContext context)
{
try {
Skin skin = getInternalSkinManager().getSkin(skinId);
Resource<?> resource = skin.getLocalResource(filename);
if (resource != null) {
return resource.getURL(forceSkinAction);
}
// Look for a resource file
if (resourceExists("/resources/" + filename)) {
XWikiURLFactory urlf = context.getURLFactory();
URL url = urlf.createResourceURL(filename, forceSkinAction, context);
return urlf.getURL(url, context);
}
} catch (Exception e) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Exception while getting skin file [{}] from skin [{}]", filename, skinId, e);
}
}
return null;
}
/**
* @deprecated since 7.0M1, use {@link SkinManager#getCurrentSkin(boolean)} instead
*/
@Deprecated
public String getSkin(XWikiContext context)
{
String skin;
try {
skin = getInternalSkinManager().getCurrentSkinId(true);
} catch (Exception e) {
LOGGER.debug("Exception while determining current skin", e);
skin = getDefaultBaseSkin(context);
}
return skin;
}
public String getSkinPreference(String prefname, XWikiContext context)
{
return getSkinPreference(prefname, "", context);
}
public String getSkinPreference(String prefname, String defaultValue, XWikiContext context)
{
for (Skin skin = getInternalSkinManager().getCurrentSkin(true); skin != null; skin = skin.getParent()) {
if (skin instanceof WikiSkin) {
String value = getWikiSkinUtils().getSkinProperty(skin.getId(), prefname);
// TODO: remove the NO_VALUE test when XWIKI-10853 is fixed
if (!StringUtils.isEmpty(value) && !NO_VALUE.equals(value)) {
return value;
}
}
}
return defaultValue;
}
/**
* @deprecated since 7.0M1, use {@link SkinManager#getDefaultParentSkin()} instead
*/
@Deprecated
public String getDefaultBaseSkin(XWikiContext context)
{
return getInternalSkinManager().getDefaultParentSkinId();
}
/**
* @deprecated since 7.0M1
*/
@Deprecated
public String getBaseSkin(XWikiContext context)
{
return getBaseSkin(context, false);
}
/**
* @deprecated since 7.0M1
*/
@Deprecated
public String getBaseSkin(XWikiContext context, boolean fromRenderSkin)
{
String baseskin = "";
try {
return getInternalSkinManager().getCurrentParentSkinId(false);
} catch (Exception e) {
baseskin = getDefaultBaseSkin(context);
LOGGER.debug("Exception while determining base skin", e);
}
return baseskin;
}
/**
* @param skin the name of the skin for which to return the base skin. For example : <tt>XWiki.DefaultSkin</tt>
* @param context see {@link XWikiContext}
* @return if found, the name of the base skin the asked skin inherits from. If not found, returns an empty string.
* @since 2.0.2
* @since 2.1M1
* @deprecated since 7.0M1, use {@link SkinManager#getCurrentSkin(boolean)} and {@link Skin#getParent()} instead
*/
@Deprecated
public String getBaseSkin(String skin, XWikiContext context)
{
String baseSkin = getInternalSkinManager().getParentSkin(skin);
return baseSkin != null ? baseSkin : "";
}
public String getSpaceCopyright(XWikiContext context)
{
return getSpacePreference("webcopyright", "", context);
}
public String getXWikiPreference(String prefname, XWikiContext context)
{
return getXWikiPreference(prefname, "", context);
}
/**
* Obtain a preference value for the wiki, looking up first in the XWiki.XWikiPreferences document, then fallbacking
* on a config parameter when the first lookup gives an empty string, then returning the default value if the config
* parameter returned itself an empty string.
*
* @param prefname the parameter to look for in the XWiki.XWikiPreferences object in the XWiki.XWikiPreferences
* document of the wiki.
* @param fallbackParam the parameter in xwiki.cfg to fallback on, in case the XWiki.XWikiPreferences object gave no
* result
* @param defaultValue the default value to fallback on, in case both XWiki.XWikiPreferences and the fallback
* xwiki.cfg parameter gave no result
*/
public String getXWikiPreference(String prefname, String fallbackParam, String defaultValue, XWikiContext context)
{
String result = getWikiConfiguration().getProperty(prefname, String.class);
if (StringUtils.isEmpty(result)) {
result = getConfiguration().getProperty(fallbackParam, defaultValue);
}
return result != null ? result : "";
}
/**
* Obtain a preference value for the wiki, looking up first in the XWiki.XWikiPreferences document, then fallbacking
* on a config parameter when the first lookup gives an empty string, then returning the default value if the config
* parameter returned itself an empty string.
*
* @param prefname the parameter to look for in the XWiki.XWikiPreferences object in the XWiki.XWikiPreferences
* document of the wiki.
* @param wiki the wiki to get preference from
* @param fallbackParam the parameter in xwiki.cfg to fallback on, in case the XWiki.XWikiPreferences object gave no
* result
* @param defaultValue the default value to fallback on, in case both XWiki.XWikiPreferences and the fallback
* xwiki.cfg parameter gave no result
* @since 7.4M1
*/
public String getXWikiPreference(String prefname, String wiki, String fallbackParam, String defaultValue,
XWikiContext xcontext)
{
String currentWiki = xcontext.getWikiId();
try {
xcontext.setWikiId(wiki);
return getXWikiPreference(prefname, fallbackParam, defaultValue, xcontext);
} finally {
xcontext.setWikiId(currentWiki);
}
}
public String getXWikiPreference(String prefname, String defaultValue, XWikiContext context)
{
return getXWikiPreference(prefname, "", defaultValue, context);
}
public String getSpacePreference(String preference, XWikiContext context)
{
return getSpacePreference(preference, "", context);
}
public String getSpacePreference(String preference, String defaultValue, XWikiContext context)
{
return getSpacePreference(preference, (SpaceReference) null, defaultValue, context);
}
/**
* @deprecated since 7.4M1, use {@link #getSpacePreference(String, SpaceReference, String, XWikiContext)} instead
*/
@Deprecated
public String getSpacePreference(String preference, String space, String defaultValue, XWikiContext context)
{
return getSpacePreference(preference, new SpaceReference(space, context.getWikiReference()), defaultValue,
context);
}
/**
* Get the reference of the space and fallback on parent space or wiki in case nothing is found.
* <p>
* If the property is not set on any level then empty String is returned.
*
* @param preferenceKey the name of the preference key
* @param spaceReference the reference of the space
* @param context see {@link XWikiContext}
* @return the value of the preference or empty String if it could not be found
* @since 7.4M1
*/
public String getSpacePreference(String preferenceKey, SpaceReference spaceReference, XWikiContext context)
{
return getSpacePreference(preferenceKey, spaceReference, "", context);
}
/**
* Get the reference of the space and fallback on parent space or wiki in case nothing is found.
* <p>
* If the property is not set on any level then <code>defaultValue</code> is returned.
*
* @param preferenceKey the name of the preference key
* @param spaceReference the reference of the space
* @param defaultValue the value to return if the preference can't be found
* @param context see {@link XWikiContext}
* @return the value of the preference or <code>defaultValue</code> if it could not be found
* @since 7.4M1
*/
public String getSpacePreference(String preferenceKey, SpaceReference spaceReference, String defaultValue,
XWikiContext context)
{
XWikiDocument currentDocument = context.getDoc();
try {
if (spaceReference != null) {
context.setDoc(new XWikiDocument(new DocumentReference("WebPreferences", spaceReference)));
} else if (currentDocument != null) {
spaceReference = currentDocument.getDocumentReference().getLastSpaceReference();
}
String result = getSpaceConfiguration().getProperty(preferenceKey, String.class);
if (StringUtils.isEmpty(result)) {
if (spaceReference == null) {
result = getXWikiPreference(preferenceKey, defaultValue, context);
} else if (spaceReference.getParent() instanceof SpaceReference) {
result = getSpacePreference(preferenceKey, (SpaceReference) spaceReference.getParent(),
defaultValue, context);
} else if (spaceReference.getParent() instanceof WikiReference) {
result =
getXWikiPreference(preferenceKey, spaceReference.getParent().getName(), defaultValue, context);
}
}
return result != null ? result : defaultValue;
} finally {
context.setDoc(currentDocument);
}
}
public String getUserPreference(String prefname, XWikiContext context)
{
String result = getUserConfiguration().getProperty(prefname, String.class);
if (StringUtils.isEmpty(result)) {
result = getSpacePreference(prefname, context);
}
return result != null ? result : "";
}
public String getUserPreferenceFromCookie(String prefname, XWikiContext context)
{
Cookie[] cookies = context.getRequest().getCookies();
if (cookies == null) {
return null;
}
for (Cookie cookie : cookies) {
String name = cookie.getName();
if (name.equals(prefname)) {
String value = cookie.getValue();
if (!value.trim().equals("")) {
return value;
} else {
break;
}
}
}
return null;
}
public String getUserPreference(String prefname, boolean useCookie, XWikiContext context)
{
// First we look in the cookies
if (useCookie) {
String result = Util.normalizeLanguage(getUserPreferenceFromCookie(prefname, context));
if (result != null) {
return result;
}
}
return getUserPreference(prefname, context);
}
/**
* First try to find the current locale in use from the XWiki context. If none is used and if the wiki is not
* multilingual use the default locale defined in the XWiki preferences. If the wiki is multilingual try to get the
* locale passed in the request. If none was passed try to get it from a cookie. If no locale cookie exists then use
* the user default locale and barring that use the browser's "Accept-Language" header sent in HTTP request. If none
* is defined use the default locale.
*
* @return the locale to use
* @since 8.0M1
*/
public Locale getLocalePreference(XWikiContext context)
{
String language = getLanguagePreference(context);
return LocaleUtils.toLocale(language);
}
/**
* First try to find the current locale in use from the XWiki context. If none is used and if the wiki is not
* multilingual use the default locale defined in the XWiki preferences. If the wiki is multilingual try to get the
* locale passed in the request. If none was passed try to get it from a cookie. If no locale cookie exists then use
* the user default locale and barring that use the browser's "Accept-Language" header sent in HTTP request. If none
* is defined use the default locale.
*
* @return the locale to use
* @deprecated since 8.0M1, use {@link #getLocalePreference(XWikiContext)} instead
*/
@Deprecated
// TODO: move implementation to #getLocalePreference
public String getLanguagePreference(XWikiContext context)
{
// First we try to get the language from the XWiki Context. This is the current language
// being used.
String language = context.getLanguage();
if (language != null) {
return language;
}
String defaultLanguage = getDefaultLanguage(context);
// If the wiki is non multilingual then the language is the default language.
if (!context.getWiki().isMultiLingual(context)) {
language = defaultLanguage;
context.setLanguage(language);
return language;
}
// As the wiki is multilingual try to find the language to use from the request by looking
// for a language parameter. If the language value is "default" use the default language
// from the XWiki preferences settings. Otherwise set a cookie to remember the language
// in use.
try {
language = Util.normalizeLanguage(context.getRequest().getParameter("language"));
if ((language != null) && (!language.equals(""))) {
if (language.equals("default")) {
// forgetting language cookie
Cookie cookie = new Cookie("language", "");
cookie.setMaxAge(0);
cookie.setPath("/");
context.getResponse().addCookie(cookie);
language = defaultLanguage;
} else {
// setting language cookie
Cookie cookie = new Cookie("language", language);
cookie.setMaxAge(60 * 60 * 24 * 365 * 10);
cookie.setPath("/");
context.getResponse().addCookie(cookie);
}
context.setLanguage(language);
return language;
}
} catch (Exception e) {
}
// As no language parameter was passed in the request, try to get the language to use
// from a cookie.
try {
// First we get the language from the cookie
language = Util.normalizeLanguage(getUserPreferenceFromCookie("language", context));
if ((language != null) && (!language.equals(""))) {
context.setLanguage(language);
return language;
}
} catch (Exception e) {
}
// Next from the default user preference
try {
String user = context.getUser();
XWikiDocument userdoc = null;
userdoc = getDocument(user, context);
if (userdoc != null) {
language = Util.normalizeLanguage(userdoc.getStringValue("XWiki.XWikiUsers", "default_language"));
if (!language.equals("")) {
context.setLanguage(language);
return language;
}
}
} catch (XWikiException e) {
}
// If the default language is preferred, and since the user didn't explicitly ask for a
// language already, then use the default wiki language.
if (getConfiguration().getProperty("xwiki.language.preferDefault", "0").equals("1")
|| getSpacePreference("preferDefaultLanguage", "0", context).equals("1")) {
language = defaultLanguage;
context.setLanguage(language);
return language;
}
// Then from the navigator language setting
if (context.getRequest() != null) {
String acceptHeader = context.getRequest().getHeader("Accept-Language");
// If the client didn't specify some languages, skip this phase
if ((acceptHeader != null) && (!acceptHeader.equals(""))) {
List<String> acceptedLanguages = getAcceptedLanguages(context.getRequest());
// We can force one of the configured languages to be accepted
if (getConfiguration().getProperty("xwiki.language.forceSupported", "0").equals("1")) {
List<String> available = Arrays.asList(getXWikiPreference("languages", context).split("[, |]"));
// Filter only configured languages
acceptedLanguages.retainAll(available);
}
if (acceptedLanguages.size() > 0) {
// Use the "most-preferred" language, as requested by the client.
context.setLanguage(acceptedLanguages.get(0));
return acceptedLanguages.get(0);
}
// If none of the languages requested by the client is acceptable, skip to next
// phase (use default language).
}
}
// Finally, use the default language from the global preferences.
context.setLanguage(defaultLanguage);
return defaultLanguage;
}
/**
* Construct a list of language codes (ISO 639-1) from the Accept-Languages header. This method filters out some
* bugs in different browsers or containers, like returning '*' as a language (Jetty) or using '_' as a
* language--country delimiter (some versions of Opera).
*
* @param request The client request.
* @return A list of language codes, in the client preference order; might be empty if the header is not well
* formed.
*/
private List<String> getAcceptedLanguages(XWikiRequest request)
{
List<String> result = new ArrayList<String>();
Enumeration<Locale> e = request.getLocales();
while (e.hasMoreElements()) {
String language = e.nextElement().getLanguage().toLowerCase();
// All language codes should have 2 letters.
if (StringUtils.isAlpha(language)) {
result.add(language);
}
}
return result;
}
/**
* @deprecated since 5.1M2 use {@link #getDefaultLocale(XWikiContext)} instead
*/
@Deprecated
public String getDefaultLanguage(XWikiContext xcontext)
{
return getDefaultLocale(xcontext).toString();
}
/**
* The default locale in the preferences.
*
* @param xcontext the XWiki context.
* @return the default locale
* @since 5.1M2
*/
public Locale getDefaultLocale(XWikiContext xcontext)
{
// Find out what is the default language from the XWiki preferences settings.
String defaultLanguage = xcontext.getWiki().getXWikiPreference("default_language", "", xcontext);
Locale defaultLocale;
if (StringUtils.isBlank(defaultLanguage)) {
defaultLocale = Locale.ENGLISH;
} else {
try {
defaultLocale = LocaleUtils.toLocale(Util.normalizeLanguage(defaultLanguage));
} catch (Exception e) {
LOGGER.warn("Invalid locale [{}] set as default locale in the preferences", defaultLanguage);
defaultLocale = Locale.ENGLISH;
}
}
return defaultLocale;
}
/**
* Get the available locales according to the preferences.
*
* @param xcontext the XWiki context
* @return all the available locales
* @since 5.1M2
*/
public List<Locale> getAvailableLocales(XWikiContext xcontext)
{
String[] languages = StringUtils.split(xcontext.getWiki().getXWikiPreference("languages", xcontext), ", |");
List<Locale> locales = new ArrayList<Locale>(languages.length);
for (String language : languages) {
if (StringUtils.isNotBlank(language)) {
try {
locales.add(LocaleUtils.toLocale(language));
} catch (Exception e) {
LOGGER.warn("Invalid locale [{}] listed as available in the preferences", language);
}
}
}
// Add default language in case it's not listed as available (which is wrong but it happen)
Locale defaultocale = getDefaultLocale(xcontext);
if (!locales.contains(defaultocale)) {
locales.add(defaultocale);
}
return locales;
}
/**
* @since 8.0M1
*/
public Locale getDocLocalePreferenceNew(XWikiContext context)
{
String language = getDocLanguagePreferenceNew(context);
return LocaleUtils.toLocale(language);
}
/**
* @deprecated since 8.0M1, use {@link #getDocLocalePreferenceNew(XWikiContext)} instead
*/
@Deprecated
// TODO: move implementation to #getDocLocalePreferenceNew
public String getDocLanguagePreferenceNew(XWikiContext context)
{
// Get context language
String contextLanguage = context.getLanguage();
// If the language exists in the context, it was previously set by another call
if (contextLanguage != null && contextLanguage != "") {
return contextLanguage;
}
String language = "", requestLanguage = "", userPreferenceLanguage = "", navigatorLanguage = "",
cookieLanguage = "";
boolean setCookie = false;
if (!context.getWiki().isMultiLingual(context)) {
language = context.getWiki().getXWikiPreference("default_language", "", context);
context.setLanguage(language);
return language;
}
// Get request language
try {
requestLanguage = Util.normalizeLanguage(context.getRequest().getParameter("language"));
} catch (Exception ex) {
}
// Get user preference
try {
String user = context.getUser();
XWikiDocument userdoc = getDocument(user, context);
if (userdoc != null) {
userPreferenceLanguage = userdoc.getStringValue("XWiki.XWikiUsers", "default_language");
}
} catch (XWikiException e) {
}
// Get navigator language setting
if (context.getRequest() != null) {
String accept = context.getRequest().getHeader("Accept-Language");
if ((accept != null) && (!accept.equals(""))) {
String[] alist = StringUtils.split(accept, ",;-");
if ((alist != null) && !(alist.length == 0)) {
context.setLanguage(alist[0]);
navigatorLanguage = alist[0];
}
}
}
// Get language from cookie
try {
cookieLanguage = Util.normalizeLanguage(getUserPreferenceFromCookie("language", context));
} catch (Exception e) {
}
// Determine which language to use
// First we get the language from the request
if (StringUtils.isNotEmpty(requestLanguage)) {
if (requestLanguage.equals("default")) {
setCookie = true;
} else {
language = requestLanguage;
context.setLanguage(language);
Cookie cookie = new Cookie("language", language);
cookie.setMaxAge(60 * 60 * 24 * 365 * 10);
cookie.setPath("/");
context.getResponse().addCookie(cookie);
return language;
}
}
// Next we get the language from the cookie
if (StringUtils.isNotEmpty(cookieLanguage)) {
language = cookieLanguage;
}
// Next from the default user preference
else if (StringUtils.isNotEmpty(userPreferenceLanguage)) {
language = userPreferenceLanguage;
}
// Then from the navigator language setting
else if (StringUtils.isNotEmpty(navigatorLanguage)) {
language = navigatorLanguage;
}
context.setLanguage(language);
if (setCookie) {
Cookie cookie = new Cookie("language", language);
cookie.setMaxAge(60 * 60 * 24 * 365 * 10);
cookie.setPath("/");
context.getResponse().addCookie(cookie);
}
return language;
}
/**
* @since 8.0M1
*/
public Locale getInterfaceLocalePreference(XWikiContext context)
{
String language = getInterfaceLanguagePreference(context);
return LocaleUtils.toLocale(language);
}
/**
* @deprecated since 8.0M1, use {@link #getInterfaceLocalePreference(XWikiContext)} instead
*/
@Deprecated
// TODO: move implementation to #getInterfaceLocalePreference
public String getInterfaceLanguagePreference(XWikiContext context)
{
String language = "", requestLanguage = "", userPreferenceLanguage = "", navigatorLanguage = "",
cookieLanguage = "", contextLanguage = "";
boolean setCookie = false;
if (!context.getWiki().isMultiLingual(context)) {
language = Util.normalizeLanguage(context.getWiki().getXWikiPreference("default_language", "", context));
context.setInterfaceLanguage(language);
return language;
}
// Get request language
try {
requestLanguage = Util.normalizeLanguage(context.getRequest().getParameter("interfacelanguage"));
} catch (Exception ex) {
}
// Get context language
contextLanguage = context.getInterfaceLanguage();
// Get user preference
try {
String user = context.getUser();
XWikiDocument userdoc = null;
userdoc = getDocument(user, context);
if (userdoc != null) {
userPreferenceLanguage = userdoc.getStringValue("XWiki.XWikiUsers", "default_interface_language");
}
} catch (XWikiException e) {
}
// Get navigator language setting
if (context.getRequest() != null) {
String accept = context.getRequest().getHeader("Accept-Language");
if ((accept != null) && (!accept.equals(""))) {
String[] alist = StringUtils.split(accept, ",;-");
if ((alist != null) && !(alist.length == 0)) {
context.setLanguage(alist[0]);
navigatorLanguage = alist[0];
}
}
}
// Get language from cookie
try {
cookieLanguage = Util.normalizeLanguage(getUserPreferenceFromCookie("interfacelanguage", context));
} catch (Exception e) {
}
// Determine which language to use
// First we get the language from the request
if ((requestLanguage != null) && (!requestLanguage.equals(""))) {
if (requestLanguage.equals("default")) {
setCookie = true;
} else {
language = requestLanguage;
context.setLanguage(language);
Cookie cookie = new Cookie("interfacelanguage", language);
cookie.setMaxAge(60 * 60 * 24 * 365 * 10);
cookie.setPath("/");
context.getResponse().addCookie(cookie);
return language;
}
}
// Next we get the language from the context
if (contextLanguage != null && contextLanguage != "") {
language = contextLanguage;
}
// Next we get the language from the cookie
else if (StringUtils.isNotEmpty(cookieLanguage)) {
language = cookieLanguage;
}
// Next from the default user preference
else if (StringUtils.isNotEmpty(userPreferenceLanguage)) {
language = userPreferenceLanguage;
}
// Then from the navigator language setting
else if (StringUtils.isNotEmpty(navigatorLanguage)) {
language = navigatorLanguage;
}
context.setLanguage(language);
if (setCookie) {
Cookie cookie = new Cookie("interfacelanguage", language);
cookie.setMaxAge(60 * 60 * 24 * 365 * 10);
cookie.setPath("/");
context.getResponse().addCookie(cookie);
}
return language;
}
public long getXWikiPreferenceAsLong(String preference, XWikiContext context)
{
return Long.parseLong(getXWikiPreference(preference, context));
}
public long getSpacePreferenceAsLong(String preference, XWikiContext context)
{
return Long.parseLong(getSpacePreference(preference, context));
}
public long getXWikiPreferenceAsLong(String preference, long defaultValue, XWikiContext context)
{
return NumberUtils.toLong((getXWikiPreference(preference, context)), defaultValue);
}
public long getXWikiPreferenceAsLong(String preference, String fallbackParameter, long defaultValue,
XWikiContext context)
{
return NumberUtils.toLong(getXWikiPreference(preference, fallbackParameter, "", context), defaultValue);
}
public long getSpacePreferenceAsLong(String preference, long defaultValue, XWikiContext context)
{
return NumberUtils.toLong(getSpacePreference(preference, context), defaultValue);
}
public long getUserPreferenceAsLong(String preference, XWikiContext context)
{
return Long.parseLong(getUserPreference(preference, context));
}
public int getXWikiPreferenceAsInt(String preference, XWikiContext context)
{
return Integer.parseInt(getXWikiPreference(preference, context));
}
public int getSpacePreferenceAsInt(String preference, XWikiContext context)
{
return Integer.parseInt(getSpacePreference(preference, context));
}
public int getXWikiPreferenceAsInt(String preference, int defaultValue, XWikiContext context)
{
return NumberUtils.toInt(getXWikiPreference(preference, context), defaultValue);
}
public int getXWikiPreferenceAsInt(String preference, String fallbackParameter, int defaultValue,
XWikiContext context)
{
return NumberUtils.toInt(getXWikiPreference(preference, fallbackParameter, "", context), defaultValue);
}
public int getSpacePreferenceAsInt(String preference, int defaultValue, XWikiContext context)
{
return NumberUtils.toInt(getSpacePreference(preference, context), defaultValue);
}
public int getUserPreferenceAsInt(String prefname, XWikiContext context)
{
return Integer.parseInt(getUserPreference(prefname, context));
}
public void flushCache(XWikiContext context)
{
// We need to flush the virtual wiki list
this.initializedWikis = new ConcurrentHashMap<>();
// We need to flush the group service cache
if (this.groupService != null) {
this.groupService.flushCache();
}
// If we use the Cache Store layer.. we need to flush it
XWikiStoreInterface store = getStore();
if ((store != null) && (store instanceof XWikiCacheStoreInterface)) {
((XWikiCacheStoreInterface) getStore()).flushCache();
}
// Flush renderers.. Groovy renderer has a cache
getOldRendering().flushCache();
getParseGroovyFromString().flushCache();
XWikiPluginManager pmanager = getPluginManager();
if (pmanager != null) {
pmanager.flushCache(context);
}
// Make sure we call all classes flushCache function
try {
List<String> classes = getClassList(context);
for (int i = 0; i < classes.size(); i++) {
String className = classes.get(i);
try {
getClass(className, context).flushCache();
} catch (Exception e) {
}
}
} catch (Exception e) {
}
}
public XWikiPluginManager getPluginManager()
{
return this.pluginManager;
}
public void setPluginManager(XWikiPluginManager pluginManager)
{
this.pluginManager = pluginManager;
}
public void setStore(XWikiStoreInterface store)
{
this.store = store;
}
public void setAttachmentStore(XWikiAttachmentStoreInterface attachmentStore)
{
this.attachmentStore = attachmentStore;
}
public void setAttachmentVersioningStore(AttachmentVersioningStore avStore)
{
this.attachmentVersioningStore = avStore;
}
public void setVersioningStore(XWikiVersioningStoreInterface versioningStore)
{
this.versioningStore = versioningStore;
}
public void setRecycleBinStore(XWikiRecycleBinStoreInterface recycleBinStore)
{
this.recycleBinStore = recycleBinStore;
}
public void setAttachmentRecycleBinStore(AttachmentRecycleBinStore attachmentRecycleBinStore)
{
this.attachmentRecycleBinStore = attachmentRecycleBinStore;
}
public void setCriteriaService(XWikiCriteriaService criteriaService)
{
this.criteriaService = criteriaService;
}
public void setVersion(String version)
{
this.version = version;
}
/**
* Verify if the provided xclass page exists and that it contains all the required configuration properties to make
* the tag feature work properly. If some properties are missing they are created and saved in the database.
*
* @param context see {@link XWikiContext}
* @param classReference the reference of the document containing the class
* @return the Base Class object containing the properties
* @throws XWikiException if an error happens during the save to the database
*/
private BaseClass getMandatoryClass(XWikiContext context, DocumentReference classReference) throws XWikiException
{
XWikiDocument document = getDocument(classReference, context);
if (context.get("initdone") == null) {
@SuppressWarnings("deprecation")
MandatoryDocumentInitializer initializer =
Utils.getComponent(MandatoryDocumentInitializer.class, document.getFullName());
if (initializer.updateDocument(document)) {
saveDocument(document, localizePlainOrKey("core.model.xclass.mandatoryUpdateProperty.versionSummary"),
context);
}
}
return document.getXClass();
}
/**
* Verify if the <code>XWiki.TagClass</code> page exists and that it contains all the required configuration
* properties to make the tag feature work properly. If some properties are missing they are created and saved in
* the database.
*
* @param context see {@link XWikiContext}
* @return the TagClass Base Class object containing the properties
* @throws XWikiException if an error happens during the save to the datavase
*/
public BaseClass getTagClass(XWikiContext context) throws XWikiException
{
return getMandatoryClass(context, new DocumentReference(context.getWikiId(), SYSTEM_SPACE, "TagClass"));
}
/**
* Verify if the <code>XWiki.SheetClass</code> page exists and that it contains all the required configuration
* properties to make the sheet feature work properly. If some properties are missing they are created and saved in
* the database. SheetClass is used to a page as a sheet. When a page is tagged as a sheet and that page is included
* in another page using the include macro then editing it triggers automatic inline edition (for XWiki Syntax 2.0
* only - for XWiki Syntax 1.0 automatic inline edition is triggered using #includeForm).
*
* @param context see {@link XWikiContext}
* @return the SheetClass Base Class object containing the properties
* @throws XWikiException if an error happens during the save to the database
* @deprecated since 3.1M2 edit mode class should be used for this purpose, not the sheet class
* @see #getEditModeClass(XWikiContext)
*/
@Deprecated
public BaseClass getSheetClass(XWikiContext context) throws XWikiException
{
return getMandatoryClass(context, new DocumentReference(context.getWikiId(), SYSTEM_SPACE, "SheetClass"));
}
/**
* Verify if the {@code XWiki.EditModeClass} page exists and that it contains all the required configuration
* properties to make the edit mode feature work properly. If some properties are missing they are created and saved
* in the database. EditModeClass is used to specify the default edit mode of a page. It can also be used to mark a
* page as a sheet. When a page is marked as a sheet and that page is included in another page using the include
* macro then editing it triggers automatic inline edition (for XWiki Syntax 2.0 only - for XWiki Syntax 1.0
* automatic inline edition is triggered using #includeForm). It replaces and enhances the SheetClass mechanism (see
* {@link #getSheetClass(XWikiContext)}).
*
* @param context see {@link XWikiContext}
* @return the EditModeClass Base Class object containing the properties
* @throws XWikiException if an error happens during the save to the database
* @since 3.1M2
*/
public BaseClass getEditModeClass(XWikiContext context) throws XWikiException
{
return getMandatoryClass(context, new DocumentReference(
new LocalDocumentReference(XWikiConstant.EDIT_MODE_CLASS), new WikiReference(context.getWikiId())));
}
/**
* Verify if the <code>XWiki.XWikiUsers</code> page exists and that it contains all the required configuration
* properties to make the user feature work properly. If some properties are missing they are created and saved in
* the database.
*
* @param context see {@link XWikiContext}
* @return the XWikiUsers Base Class object containing the properties
* @throws XWikiException if an error happens during the save to the datavase
*/
public BaseClass getUserClass(XWikiContext context) throws XWikiException
{
return getMandatoryClass(context, new DocumentReference(context.getWikiId(), SYSTEM_SPACE, "XWikiUsers"));
}
/**
* Verify if the <code>XWiki.GlobalRedirect</code> page exists and that it contains all the required configuration
* properties to make the redirection feature work properly. If some properties are missing they are created and
* saved in the database.
*
* @param context see {@link XWikiContext}
* @return the GlobalRedirect Base Class object containing the properties
* @throws XWikiException if an error happens during the save to the datavase
*/
public BaseClass getRedirectClass(XWikiContext context) throws XWikiException
{
return getMandatoryClass(context, new DocumentReference(context.getWikiId(), SYSTEM_SPACE, "GlobalRedirect"));
}
/**
* Verify if the <code>XWiki.XWikiPreferences</code> page exists and that it contains all the required configuration
* properties to make XWiki work properly. If some properties are missing they are created and saved in the
* database.
*
* @param context see {@link XWikiContext}
* @return the XWiki Base Class object containing the properties
* @throws XWikiException if an error happens during the save to the datavase
*/
public BaseClass getPrefsClass(XWikiContext context) throws XWikiException
{
return getMandatoryClass(context, getPreferencesDocumentReference(context));
}
public BaseClass getGroupClass(XWikiContext context) throws XWikiException
{
return getMandatoryClass(context, new DocumentReference(context.getWikiId(), SYSTEM_SPACE, "XWikiGroups"));
}
public BaseClass getRightsClass(String pagename, XWikiContext context) throws XWikiException
{
return getMandatoryClass(context, new DocumentReference(context.getWikiId(), SYSTEM_SPACE, pagename));
}
public BaseClass getRightsClass(XWikiContext context) throws XWikiException
{
return getRightsClass("XWikiRights", context);
}
public BaseClass getGlobalRightsClass(XWikiContext context) throws XWikiException
{
return getRightsClass("XWikiGlobalRights", context);
}
public BaseClass getCommentsClass(XWikiContext context) throws XWikiException
{
return getMandatoryClass(context, new DocumentReference(context.getWikiId(), SYSTEM_SPACE, "XWikiComments"));
}
public BaseClass getSkinClass(XWikiContext context) throws XWikiException
{
return getMandatoryClass(context, new DocumentReference(context.getWikiId(), SYSTEM_SPACE, "XWikiSkins"));
}
public int createUser(XWikiContext context) throws XWikiException
{
return createUser(false, "edit", context);
}
public int validateUser(boolean withConfirmEmail, XWikiContext context) throws XWikiException
{
try {
XWikiRequest request = context.getRequest();
// Get the user document
String username = convertUsername(request.getParameter("xwikiname"), context);
if (username.indexOf('.') == -1) {
username = "XWiki." + username;
}
XWikiDocument userDocument = getDocument(username, context);
// Get the stored validation key
BaseObject userObject = userDocument.getObject("XWiki.XWikiUsers", 0);
String storedKey = userObject.getStringValue("validkey");
// Get the validation key from the URL
String validationKey = request.getParameter("validkey");
PropertyInterface validationKeyClass = getClass("XWiki.XWikiUsers", context).get("validkey");
if (validationKeyClass instanceof PasswordClass) {
validationKey = ((PasswordClass) validationKeyClass).getEquivalentPassword(storedKey, validationKey);
}
// Compare the two keys
if ((!storedKey.equals("") && (storedKey.equals(validationKey)))) {
userObject.setIntValue("active", 1);
saveDocument(userDocument, context);
if (withConfirmEmail) {
String email = userObject.getStringValue("email");
String password = userObject.getStringValue("password");
sendValidationEmail(username, password, email, request.getParameter("validkey"),
"confirmation_email_content", context);
}
return 0;
} else {
return -1;
}
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
throw new XWikiException(XWikiException.MODULE_XWIKI_APP, XWikiException.ERROR_XWIKI_APP_VALIDATE_USER,
"Exception while validating user", e, null);
}
}
public int createUser(boolean withValidation, String userRights, XWikiContext context) throws XWikiException
{
try {
XWikiRequest request = context.getRequest();
Map<String, String[]> map = Util.getObject(request, "register");
String content = "";
Syntax syntax = getDefaultDocumentSyntaxInternal();
// Read the values from the request.
String xwikiname = request.getParameter("xwikiname");
String password2 = request.getParameter("register2_password");
String password = (map.get("password"))[0];
String email = (map.get("email"))[0];
String template = request.getParameter("template");
String parent = request.getParameter("parent");
String validkey = null;
// Validate the values.
if (XWikiRightService.SUPERADMIN_USER.equalsIgnoreCase(xwikiname)) {
return -8;
}
try {
if (!context.getUtil().match(getConfiguration().getProperty("xwiki.validusername", "/^[a-zA-Z0-9_]+$/"),
xwikiname)) {
return -4;
}
} catch (RuntimeException ex) {
LOGGER.warn("Invalid regular expression for xwiki.validusername", ex);
if (!context.getUtil().match("/^[a-zA-Z0-9_]+$/", xwikiname)) {
return -4;
}
}
if ((!password.equals(password2)) || (password.trim().equals(""))) {
// TODO: throw wrong password exception
return -2;
}
if ((template != null) && (!template.equals(""))) {
XWikiDocument tdoc = getDocument(template, context);
if ((!tdoc.isNew())) {
// FIXME: This ignores template objects, attachments, etc.
content = tdoc.getContent();
syntax = tdoc.getSyntax();
}
}
if ((parent == null) || (parent.equals(""))) {
parent = "XWiki.XWikiUsers";
}
// Mark the user as active or waiting email validation.
if (withValidation) {
map.put("active", new String[] { "0" });
validkey = generateValidationKey(16);
map.put("validkey", new String[] { validkey });
} else {
// Mark user active
map.put("active", new String[] { "1" });
}
// Create the user.
int result =
createUser(xwikiname, map, getRelativeEntityReferenceResolver().resolve(parent, EntityType.DOCUMENT),
content, syntax, userRights, context);
// Send validation mail, if needed.
if ((result > 0) && (withValidation)) {
// Send the validation email
try {
sendValidationEmail(xwikiname, password, email, validkey, "validation_email_content", context);
} catch (XWikiException e) {
LOGGER.warn("User created. Failed to send the mail to the created user.", e);
return -11;
}
}
return result;
} catch (XWikiException e) {
LOGGER.error(e.getMessage(), e);
throw e;
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
throw new XWikiException(XWikiException.MODULE_XWIKI_APP, XWikiException.ERROR_XWIKI_APP_CREATE_USER,
"Exception while creating user", e, null);
}
}
/**
* Method allows to create an empty user with no password (he won't be able to login) This method is usefull for
* authentication like LDAP or App Server trusted
*
* @param xwikiname
* @param userRights
* @param context see {@link XWikiContext}
* @return true if success
* @throws XWikiException
*/
public boolean createEmptyUser(String xwikiname, String userRights, XWikiContext context) throws XWikiException
{
Map<String, String> map = new HashMap<String, String>();
map.put("active", "1");
map.put("first_name", xwikiname);
if (createUser(xwikiname, map, userRights, context) == 1) {
return true;
} else {
return false;
}
}
public void sendConfirmationEmail(String xwikiname, String password, String email, String message,
String contentfield, XWikiContext context) throws XWikiException
{
sendValidationEmail(xwikiname, password, email, "message", message, contentfield, context);
}
public void sendValidationEmail(String xwikiname, String password, String email, String validkey,
String contentfield, XWikiContext context) throws XWikiException
{
sendValidationEmail(xwikiname, password, email, "validkey", validkey, contentfield, context);
}
public void sendValidationEmail(String xwikiname, String password, String email, String addfieldname,
String addfieldvalue, String contentfield, XWikiContext context) throws XWikiException
{
MailSenderConfiguration configuration = Utils.getComponent(MailSenderConfiguration.class);
String sender;
String content;
try {
sender = configuration.getFromAddress();
if (StringUtils.isBlank(sender)) {
String server = context.getRequest().getServerName();
if (server.matches("\\[.*\\]|(\\d{1,3}+\\.){3}+\\d{1,3}+")) {
sender = "noreply@domain.net";
} else {
sender = "noreply@" + server;
}
}
content = getXWikiPreference(contentfield, context);
} catch (Exception e) {
throw new XWikiException(XWikiException.MODULE_XWIKI_EMAIL,
XWikiException.ERROR_XWIKI_EMAIL_CANNOT_GET_VALIDATION_CONFIG,
"Exception while reading the validation email config", e, null);
}
try {
VelocityContext vcontext = (VelocityContext) context.get("vcontext");
vcontext.put(addfieldname, addfieldvalue);
vcontext.put("email", email);
vcontext.put("password", password);
vcontext.put("sender", sender);
vcontext.put("xwikiname", xwikiname);
content = parseContent(content, context);
} catch (Exception e) {
throw new XWikiException(XWikiException.MODULE_XWIKI_EMAIL,
XWikiException.ERROR_XWIKI_EMAIL_CANNOT_PREPARE_VALIDATION_EMAIL,
"Exception while preparing the validation email", e, null);
}
// Let's now send the message
try {
Session session =
Session.getInstance(configuration.getAllProperties(), new XWikiAuthenticator(configuration));
InputStream is = new ByteArrayInputStream(content.getBytes());
MimeMessage message = new MimeMessage(session, is);
message.setFrom(new InternetAddress(sender));
message.setRecipients(Message.RecipientType.TO, email);
message.setHeader("X-MailType", "Account Validation");
MailSender mailSender = Utils.getComponent(MailSender.class);
MailListener mailListener = Utils.getComponent(MailListener.class, "database");
mailSender.sendAsynchronously(Arrays.asList(message), session, mailListener);
mailListener.getMailStatusResult().waitTillProcessed(Long.MAX_VALUE);
String errorMessage = MailStatusResultSerializer.serializeErrors(mailListener.getMailStatusResult());
if (errorMessage != null) {
throw new XWikiException(XWikiException.MODULE_XWIKI_EMAIL,
XWikiException.ERROR_XWIKI_EMAIL_ERROR_SENDING_EMAIL,
String.format("Error while sending the validation email. %s", errorMessage));
}
} catch (Exception e) {
throw new XWikiException(XWikiException.MODULE_XWIKI_EMAIL,
XWikiException.ERROR_XWIKI_EMAIL_ERROR_SENDING_EMAIL, "Error while sending the validation email", e);
}
}
public String generateRandomString(int size)
{
return RandomStringUtils.randomAlphanumeric(size);
}
public String generateValidationKey(int size)
{
return generateRandomString(size);
}
/**
* Create a new user.
*
* @param userName the name of the user (without the space)
* @param map extra datas to add to user profile object
* @param context see {@link XWikiContext}
* @return
* <ul>
* <li>1: ok</li>
* <li>-3: user already exists</li>
* </ul>
* @throws XWikiException failed to create the new user
*/
public int createUser(String userName, Map<String, ?> map, XWikiContext context) throws XWikiException
{
return createUser(userName, map, "edit", context);
}
/**
* Create a new user.
*
* @param userName the name of the user (without the space)
* @param map extra datas to add to user profile object
* @param userRights the right of the user on his own profile page
* @param context see {@link XWikiContext}
* @return
* <ul>
* <li>1: ok</li>
* <li>-3: user already exists</li>
* </ul>
* @throws XWikiException failed to create the new user
*/
public int createUser(String userName, Map<String, ?> map, String userRights, XWikiContext context)
throws XWikiException
{
BaseClass userClass = getUserClass(context);
String content = "";
Syntax syntax = getDefaultDocumentSyntaxInternal();
return createUser(userName, map,
new EntityReference(userClass.getDocumentReference().getName(), EntityType.DOCUMENT), content, syntax,
userRights, context);
}
/**
* @deprecated since 2.4RC1 use
* {@link #createUser(String, Map, EntityReference, String, Syntax, String, XWikiContext)} instead
*/
@Deprecated
public int createUser(String userName, Map<String, ?> map, String parent, String content, String syntaxId,
String userRights, XWikiContext context) throws XWikiException
{
Syntax syntax;
try {
syntax = getSyntaxFactory().createSyntaxFromIdString(syntaxId);
} catch (ParseException e) {
syntax = getDefaultDocumentSyntaxInternal();
}
return createUser(userName, map, getRelativeEntityReferenceResolver().resolve(parent, EntityType.DOCUMENT),
content, syntax, userRights, context);
}
/**
* Create a new user.
*
* @param userName the name of the user (without the space)
* @param map extra datas to add to user profile object
* @param parentReference the parent of the user profile
* @param content the content of the user profile
* @param syntax the syntax of the provided content
* @param userRights the right of the user on his own profile page
* @param context see {@link XWikiContext}
* @return
* <ul>
* <li>1: ok</li>
* <li>-3: user already exists</li>
* </ul>
* @throws XWikiException failed to create the new user
*/
public int createUser(String userName, Map<String, ?> map, EntityReference parentReference, String content,
Syntax syntax, String userRights, XWikiContext context) throws XWikiException
{
BaseClass userClass = getUserClass(context);
try {
// TODO: Verify existing user
XWikiDocument doc = getDocument(new DocumentReference(context.getWikiId(), "XWiki", userName), context);
if (!doc.isNew()) {
// TODO: throws Exception
return -3;
}
DocumentReference userClassReference = userClass.getDocumentReference();
BaseObject userObject =
doc.newXObject(userClassReference.removeParent(userClassReference.getWikiReference()), context);
userClass.fromMap(map, userObject);
doc.setParentReference(parentReference);
doc.setContent(content);
doc.setSyntax(syntax);
doc.setCreatorReference(doc.getDocumentReference());
doc.setAuthorReference(doc.getDocumentReference());
// The information from the user profile needs to be indexed using the proper locale. If multilingual is
// enabled then the user can choose the desired locale (from the list of supported locales) before
// registering. An administrator registering users can do the same. Otherwise, if there is only one locale
// supported then that langage will be used.
doc.setDefaultLocale(context.getLocale());
protectUserPage(doc.getFullName(), userRights, doc, context);
saveDocument(doc, localizePlainOrKey("core.comment.createdUser"), context);
// Now let's add the user to XWiki.XWikiAllGroup
setUserDefaultGroup(doc.getFullName(), context);
return 1;
} catch (Exception e) {
Object[] args = { "XWiki." + userName };
throw new XWikiException(XWikiException.MODULE_XWIKI_USER, XWikiException.ERROR_XWIKI_USER_CREATE,
"Cannot create user {0}", e, args);
}
}
/**
* @deprecated starting with XE 1.8.1 use
* {@link #createUser(String, Map, String, String, String, String, XWikiContext)} instead
*/
@Deprecated
public int createUser(String xwikiname, Map<String, ?> map, String parent, String content, String userRights,
XWikiContext context) throws XWikiException
{
return createUser(xwikiname, map, parent, content, Syntax.XWIKI_1_0.toIdString(), userRights, context);
}
public void setUserDefaultGroup(String fullwikiname, XWikiContext context) throws XWikiException
{
String groupsPreference = isAllGroupImplicit() ? getConfiguration().getProperty("xwiki.users.initialGroups")
: getConfiguration().getProperty("xwiki.users.initialGroups", "XWiki.XWikiAllGroup");
if (groupsPreference != null) {
String[] groups = groupsPreference.split(",");
for (String groupName : groups) {
if (StringUtils.isNotBlank(groupName)) {
addUserToGroup(fullwikiname, groupName.trim(), context);
}
}
}
}
protected void addUserToGroup(String userName, String groupName, XWikiContext context) throws XWikiException
{
XWikiDocument groupDoc = getDocument(groupName, context);
DocumentReference groupClassReference = getGroupClass(context).getDocumentReference();
BaseObject memberObject =
groupDoc.newXObject(groupClassReference.removeParent(groupClassReference.getWikiReference()), context);
memberObject.setStringValue("member", userName);
this.saveDocument(groupDoc, localizePlainOrKey("core.comment.addedUserToGroup"), context);
}
public void protectUserPage(String userName, String userRights, XWikiDocument doc, XWikiContext context)
throws XWikiException
{
DocumentReference rightClassReference = getRightsClass(context).getDocumentReference();
EntityReference relativeRightClassReference =
rightClassReference.removeParent(rightClassReference.getWikiReference());
// Allow users to edit their own profiles
BaseObject newuserrightsobject = doc.newXObject(relativeRightClassReference, context);
newuserrightsobject.setLargeStringValue("users", userName);
newuserrightsobject.setStringValue("levels", userRights);
newuserrightsobject.setIntValue("allow", 1);
}
public User getUser(XWikiContext context)
{
XWikiUser xwikiUser = context.getXWikiUser();
User user = new User(xwikiUser, context);
return user;
}
public User getUser(String username, XWikiContext context)
{
XWikiUser xwikiUser = new XWikiUser(username);
User user = new User(xwikiUser, context);
return user;
}
/**
* Prepares the localized resources, according to the selected locale. Set context "msg" and locale.
*
* @param context see {@link XWikiContext}
*/
public void prepareResources(XWikiContext context)
{
if (context.get("msg") == null) {
Locale locale = getLocalePreference(context);
context.setLocale(locale);
if (context.getResponse() != null) {
context.getResponse().setLocale(locale);
}
XWikiMessageTool msg = new XWikiMessageTool(Utils.getComponent(ContextualLocalizationManager.class));
context.put("msg", msg);
}
}
public XWikiUser checkAuth(XWikiContext context) throws XWikiException
{
return getAuthService().checkAuth(context);
}
public boolean checkAccess(String action, XWikiDocument doc, XWikiContext context) throws XWikiException
{
// Handle the 'skin' action specially so that resources don`t require special (or even 'view') rights.
String firstSpaceName = doc.getDocumentReference().getSpaceReferences().get(0).getName();
if (action.equals("skin") && SKIN_RESOURCE_SPACE_NAMES.contains(firstSpaceName)) {
// We still need to call checkAuth to set the proper user.
XWikiUser user = checkAuth(context);
if (user != null) {
context.setUser(user.getUser());
}
// Always allow.
return true;
}
return getRightService().checkAccess(action, doc, context);
}
public String include(String topic, boolean isForm, XWikiContext context) throws XWikiException
{
String database = null, incdatabase = null;
String prefixedTopic, localTopic;
// Save current documents in script context
Document currentAPIdoc = null, currentAPIcdoc = null, currentAPItdoc = null;
ScriptContextManager scritContextManager = Utils.getComponent(ScriptContextManager.class);
ScriptContext scontext = scritContextManager.getScriptContext();
String currentDocName = context.getWikiId() + ":" + context.getDoc().getFullName();
if (scontext != null) {
currentAPIdoc = (Document) scontext.getAttribute("doc");
currentAPIcdoc = (Document) scontext.getAttribute("cdoc");
currentAPItdoc = (Document) scontext.getAttribute("tdoc");
}
try {
int i0 = topic.indexOf(':');
if (i0 != -1) {
incdatabase = topic.substring(0, i0);
database = context.getWikiId();
context.setWikiId(incdatabase);
prefixedTopic = topic;
localTopic = topic.substring(i0 + 1);
} else {
prefixedTopic = context.getWikiId() + ":" + topic;
localTopic = topic;
}
XWikiDocument doc = null;
try {
LOGGER.debug("Including Topic " + topic);
try {
@SuppressWarnings("unchecked")
Set<String> includedDocs = (Set<String>) context.get("included_docs");
if (includedDocs == null) {
includedDocs = new HashSet<String>();
context.put("included_docs", includedDocs);
}
if (includedDocs.contains(prefixedTopic) || currentDocName.equals(prefixedTopic)) {
LOGGER.warn("Error on too many recursive includes for topic " + topic);
return "Cannot make recursive include";
}
includedDocs.add(prefixedTopic);
} catch (Exception e) {
}
// Get document to include
DocumentReference targetDocumentReference =
getCurrentMixedDocumentReferenceResolver().resolve(localTopic);
doc = getDocument(targetDocumentReference, context);
if (checkAccess("view", doc, context) == false) {
throw new XWikiException(XWikiException.MODULE_XWIKI_ACCESS,
XWikiException.ERROR_XWIKI_ACCESS_DENIED, "Access to this document is denied: " + doc);
}
} catch (XWikiException e) {
LOGGER.warn("Exception Including Topic " + topic, e);
return "Topic " + topic + " does not exist";
}
XWikiDocument contentdoc = doc.getTranslatedDocument(context);
String result;
if (isForm) {
// We do everything in the context of the including document
if (database != null) {
context.setWikiId(database);
}
// Note: the Script macro in the new rendering checks for programming rights for the document in
// the xwiki context.
result = getRenderedContent(contentdoc, (XWikiDocument) context.get("doc"), context);
} else {
// We stay in the included document context
// Since the Script macro checks for programming rights in the current document, we need to
// temporarily set the contentdoc as the current doc before rendering it.
XWikiDocument originalDoc = null;
try {
originalDoc = context.getDoc();
context.put("doc", doc);
result = getRenderedContent(contentdoc, doc, context);
} finally {
context.put("doc", originalDoc);
}
}
try {
@SuppressWarnings("unchecked")
Set<String> includedDocs = (Set<String>) context.get("included_docs");
if (includedDocs != null) {
includedDocs.remove(prefixedTopic);
}
} catch (Exception e) {
}
return result;
} finally {
if (database != null) {
context.setWikiId(database);
}
if (currentAPIdoc != null) {
if (scontext != null) {
scontext.setAttribute("doc", currentAPIdoc, ScriptContext.ENGINE_SCOPE);
}
}
if (currentAPIcdoc != null) {
if (scontext != null) {
scontext.setAttribute("cdoc", currentAPIcdoc, ScriptContext.ENGINE_SCOPE);
}
}
if (currentAPItdoc != null) {
if (scontext != null) {
scontext.setAttribute("tdoc", currentAPItdoc, ScriptContext.ENGINE_SCOPE);
}
}
}
}
/**
* Render content from the passed included document, setting the correct security doc (sdoc) and including doc
* (idoc).
*
* @since 2.2M2
*/
private String getRenderedContent(XWikiDocument includedDoc, XWikiDocument includingDoc, XWikiContext context)
throws XWikiException
{
String result;
XWikiDocument idoc = (XWikiDocument) context.get("idoc");
XWikiDocument sdoc = (XWikiDocument) context.get("sdoc");
context.put("idoc", includingDoc);
context.put("sdoc", includedDoc);
try {
result = includedDoc.getRenderedContent(Utils.getComponent(RenderingContext.class).getTargetSyntax(), false,
context);
} finally {
// Remove including doc or set the previous one
if (idoc == null) {
context.remove("idoc");
} else {
context.put("idoc", idoc);
}
// Remove security doc or set the previous one
if (sdoc == null) {
context.remove("sdoc");
} else {
context.put("sdoc", sdoc);
}
}
return result;
}
public void deleteDocument(XWikiDocument doc, XWikiContext context) throws XWikiException
{
deleteDocument(doc, true, context);
}
public void deleteDocument(XWikiDocument doc, boolean totrash, XWikiContext context) throws XWikiException
{
String currentWiki = null;
currentWiki = context.getWikiId();
try {
context.setWikiId(doc.getDocumentReference().getWikiReference().getName());
// The source document is a new empty XWikiDocument to follow
// DocumentUpdatedEvent policy: source document in new document and the old version is available using
// doc.getOriginalDocument()
XWikiDocument blankDoc = new XWikiDocument(doc.getDocumentReference());
// Again to follow general event policy, new document author is the user who modified the document
// (here the modification is delete)
blankDoc.setOriginalDocument(doc.getOriginalDocument());
blankDoc.setAuthorReference(context.getUserReference());
blankDoc.setContentAuthorReference(context.getUserReference());
ObservationManager om = getObservationManager();
// Inform notification mechanisms that a document is about to be deleted
// Note that for the moment the event being send is a bridge event, as we are still passing around
// an XWikiDocument as source and an XWikiContext as data.
if (om != null) {
om.notify(new DocumentDeletingEvent(doc.getDocumentReference()), blankDoc, context);
}
if (hasRecycleBin(context) && totrash) {
// Extract (safely) any existing batchId from the context.
Object batchIdValue = Utils.getComponent(Execution.class).getContext().getProperty("BATCH_ID");
String batchId = Objects.toString(batchIdValue, null);
// Save to recycle bin together with any determined batch ID.
getRecycleBinStore().saveToRecycleBin(doc, context.getUser(), new Date(), batchId, context, true);
}
getStore().deleteXWikiDoc(doc, context);
try {
// Inform notification mechanisms that a document has been deleted
// Note that for the moment the event being send is a bridge event, as we are still passing around
// an XWikiDocument as source and an XWikiContext as data.
if (om != null) {
om.notify(new DocumentDeletedEvent(doc.getDocumentReference()), blankDoc, context);
}
} catch (Exception ex) {
LOGGER.error("Failed to send document delete notifications for document [{}]",
doc.getDocumentReference(), ex);
}
} finally {
context.setWikiId(currentWiki);
}
}
public String getDatabase()
{
return this.database;
}
public void setDatabase(String database)
{
this.database = database;
}
public void gc()
{
System.gc();
}
public long freeMemory()
{
return Runtime.getRuntime().freeMemory();
}
public long totalMemory()
{
return Runtime.getRuntime().totalMemory();
}
public long maxMemory()
{
return Runtime.getRuntime().maxMemory();
}
public String[] split(String str, String sep)
{
return StringUtils.split(str, sep);
}
/**
* @deprecated use {@link ExceptionUtils#getStackTrace(Throwable)} instead
*/
@Deprecated
public String printStrackTrace(Throwable e)
{
StringWriter strwriter = new StringWriter();
PrintWriter writer = new PrintWriter(strwriter);
e.printStackTrace(writer);
return strwriter.toString();
}
/**
* @since 2.2M2
*/
public boolean copyDocument(DocumentReference sourceDocumentReference, DocumentReference targetDocumentReference,
XWikiContext context) throws XWikiException
{
return copyDocument(sourceDocumentReference, targetDocumentReference, null, true, context);
}
/**
* @since 2.2M2
*/
public boolean copyDocument(DocumentReference sourceDocumentReference, DocumentReference targetDocumentReference,
boolean reset, XWikiContext context) throws XWikiException
{
return copyDocument(sourceDocumentReference, targetDocumentReference, null, reset, context);
}
/**
* @since 2.2M2
*/
public boolean copyDocument(DocumentReference sourceDocumentReference, DocumentReference targetDocumentReference,
boolean reset, boolean force, boolean resetCreationData, XWikiContext context) throws XWikiException
{
return copyDocument(sourceDocumentReference, targetDocumentReference, null, reset, force, resetCreationData,
context);
}
/**
* @since 2.2M2
*/
public boolean copyDocument(DocumentReference sourceDocumentReference, DocumentReference targetDocumentReference,
String wikilocale, XWikiContext context) throws XWikiException
{
return copyDocument(sourceDocumentReference, targetDocumentReference, wikilocale, true, context);
}
/**
* @since 2.2M2
*/
public boolean copyDocument(DocumentReference sourceDocumentReference, DocumentReference targetDocumentReference,
String wikilocale, boolean reset, XWikiContext context) throws XWikiException
{
return copyDocument(sourceDocumentReference, targetDocumentReference, wikilocale, reset, false, context);
}
/**
* @since 2.2M2
*/
public boolean copyDocument(DocumentReference sourceDocumentReference, DocumentReference targetDocumentReference,
String wikilocale, boolean reset, boolean force, XWikiContext context) throws XWikiException
{
return copyDocument(sourceDocumentReference, targetDocumentReference, wikilocale, reset, force, false, context);
}
/**
* @since 2.2M2
*/
public boolean copyDocument(DocumentReference sourceDocumentReference, DocumentReference targetDocumentReference,
String wikilocale, boolean reset, boolean force, boolean resetCreationData, XWikiContext context)
throws XWikiException
{
String db = context.getWikiId();
String sourceWiki = sourceDocumentReference.getWikiReference().getName();
String targetWiki = targetDocumentReference.getWikiReference().getName();
String sourceStringReference = getDefaultEntityReferenceSerializer().serialize(sourceDocumentReference);
try {
context.setWikiId(sourceWiki);
XWikiDocument sdoc = getDocument(sourceDocumentReference, context);
if (!sdoc.isNew()) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info(
"Copying document [" + sourceDocumentReference + "] to [" + targetDocumentReference + "]");
}
// Let's switch to the other database to verify if the document already exists
context.setWikiId(targetWiki);
XWikiDocument tdoc = getDocument(targetDocumentReference, context);
// There is already an existing document
if (!tdoc.isNew()) {
if (force) {
// We need to delete the previous document
deleteDocument(tdoc, context);
} else {
return false;
}
}
// Let's switch back again to the original db
context.setWikiId(sourceWiki);
if (wikilocale == null) {
tdoc = sdoc.copyDocument(targetDocumentReference, context);
// We know the target document doesn't exist and we want to save the attachments without
// incrementing their versions.
// See XWIKI-8157: The "Copy Page" action adds an extra version to the attached file
tdoc.setNew(true);
// forget past versions
if (reset) {
tdoc.setVersion("1.1");
}
if (resetCreationData) {
Date now = new Date();
tdoc.setCreationDate(now);
tdoc.setContentUpdateDate(now);
tdoc.setDate(now);
tdoc.setCreatorReference(context.getUserReference());
tdoc.setAuthorReference(context.getUserReference());
}
// We don't want to trigger a new version otherwise the version number will be wrong.
tdoc.setMetaDataDirty(false);
tdoc.setContentDirty(false);
saveDocument(tdoc, "Copied from " + sourceStringReference, context);
if (!reset) {
context.setWikiId(sourceWiki);
XWikiDocumentArchive txda = getVersioningStore().getXWikiDocumentArchive(sdoc, context);
context.setWikiId(targetWiki);
txda = txda.clone(tdoc.getId(), context);
getVersioningStore().saveXWikiDocArchive(txda, true, context);
} else {
context.setWikiId(targetWiki);
getVersioningStore().resetRCSArchive(tdoc, true, context);
}
// Now we need to copy the translations
context.setWikiId(sourceWiki);
List<String> tlist = sdoc.getTranslationList(context);
for (String clanguage : tlist) {
XWikiDocument stdoc = sdoc.getTranslatedDocument(clanguage, context);
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Copying document [" + sourceWiki + "], language [" + clanguage + "] to ["
+ targetDocumentReference + "]");
}
context.setWikiId(targetWiki);
XWikiDocument ttdoc = tdoc.getTranslatedDocument(clanguage, context);
// There is already an existing document
if (ttdoc != tdoc) {
return false;
}
// Let's switch back again to the original db
context.setWikiId(sourceWiki);
ttdoc = stdoc.copyDocument(targetDocumentReference, context);
// forget past versions
if (reset) {
ttdoc.setNew(true);
ttdoc.setVersion("1.1");
}
if (resetCreationData) {
Date now = new Date();
ttdoc.setCreationDate(now);
ttdoc.setContentUpdateDate(now);
ttdoc.setDate(now);
ttdoc.setCreatorReference(context.getUserReference());
ttdoc.setAuthorReference(context.getUserReference());
}
// we don't want to trigger a new version
// otherwise the version number will be wrong
tdoc.setMetaDataDirty(false);
tdoc.setContentDirty(false);
saveDocument(ttdoc, "Copied from " + sourceStringReference, context);
if (!reset) {
context.setWikiId(sourceWiki);
XWikiDocumentArchive txda = getVersioningStore().getXWikiDocumentArchive(sdoc, context);
context.setWikiId(targetWiki);
txda = txda.clone(tdoc.getId(), context);
getVersioningStore().saveXWikiDocArchive(txda, true, context);
} else {
getVersioningStore().resetRCSArchive(tdoc, true, context);
}
}
} else {
// We want only one language in the end
XWikiDocument stdoc = sdoc.getTranslatedDocument(wikilocale, context);
tdoc = stdoc.copyDocument(targetDocumentReference, context);
// We know the target document doesn't exist and we want to save the attachments without
// incrementing their versions.
// See XWIKI-8157: The "Copy Page" action adds an extra version to the attached file
tdoc.setNew(true);
// forget language
tdoc.setDefaultLanguage(wikilocale);
tdoc.setLanguage("");
// forget past versions
if (reset) {
tdoc.setVersion("1.1");
}
if (resetCreationData) {
Date now = new Date();
tdoc.setCreationDate(now);
tdoc.setContentUpdateDate(now);
tdoc.setDate(now);
tdoc.setCreatorReference(context.getUserReference());
tdoc.setAuthorReference(context.getUserReference());
}
// we don't want to trigger a new version
// otherwise the version number will be wrong
tdoc.setMetaDataDirty(false);
tdoc.setContentDirty(false);
saveDocument(tdoc, "Copied from " + sourceStringReference, context);
if (!reset) {
context.setWikiId(sourceWiki);
XWikiDocumentArchive txda = getVersioningStore().getXWikiDocumentArchive(sdoc, context);
context.setWikiId(targetWiki);
txda = txda.clone(tdoc.getId(), context);
getVersioningStore().saveXWikiDocArchive(txda, true, context);
} else {
getVersioningStore().resetRCSArchive(tdoc, true, context);
}
}
}
return true;
} finally {
context.setWikiId(db);
}
}
public int copySpaceBetweenWikis(String space, String sourceWiki, String targetWiki, String locale,
XWikiContext context) throws XWikiException
{
return copySpaceBetweenWikis(space, sourceWiki, targetWiki, locale, false, context);
}
public int copySpaceBetweenWikis(String space, String sourceWiki, String targetWiki, String locale, boolean clean,
XWikiContext context) throws XWikiException
{
String db = context.getWikiId();
int nb = 0;
// Workaround for XWIKI-3915: Do not use XWikiStoreInterface#searchDocumentNames since currently it has the
// side effect of hidding hidden documents and no other workaround exists than directly using
// XWikiStoreInterface#search directly
String sql = "select distinct doc.fullName from XWikiDocument as doc";
List<String> parameters = new ArrayList<String>();
if (space != null) {
sql += " where doc.space = ?";
parameters.add(space);
}
if (clean) {
try {
context.setWikiId(targetWiki);
List<String> list = getStore().search(sql, 0, 0, parameters, context);
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Deleting " + list.size() + " documents from wiki " + targetWiki);
}
for (String docname : list) {
XWikiDocument doc = getDocument(docname, context);
deleteDocument(doc, context);
}
} finally {
context.setWikiId(db);
}
}
try {
context.setWikiId(sourceWiki);
List<String> list = getStore().search(sql, 0, 0, parameters, context);
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Copying " + list.size() + " documents from wiki " + sourceWiki + " to wiki " + targetWiki);
}
WikiReference sourceWikiReference = new WikiReference(sourceWiki);
WikiReference targetWikiReference = new WikiReference(targetWiki);
for (String docname : list) {
DocumentReference sourceDocumentReference = getCurrentMixedDocumentReferenceResolver().resolve(docname);
sourceDocumentReference = sourceDocumentReference
.replaceParent(sourceDocumentReference.getWikiReference(), sourceWikiReference);
DocumentReference targetDocumentReference =
sourceDocumentReference.replaceParent(sourceWikiReference, targetWikiReference);
copyDocument(sourceDocumentReference, targetDocumentReference, locale, context);
nb++;
}
return nb;
} finally {
context.setWikiId(db);
}
}
/**
* Copy an entire wiki to a target wiki.
* <p>
* It does not override document already existing in target wiki.
*
* @param sourceWiki the source wiki identifier
* @param targetWiki the target wiki identifier
* @param locale the locale to copy
* @param context see {@link XWikiContext}
* @return the number of copied documents
* @throws XWikiException failed to copy wiki
* @deprecated since 5.3, use {@link WikiManager#copy(String, String, String, boolean, boolean, boolean)} instead
*/
@Deprecated
public int copyWiki(String sourceWiki, String targetWiki, String locale, XWikiContext context) throws XWikiException
{
return copyWiki(sourceWiki, targetWiki, locale, false, context);
}
/**
* Copy an entire wiki to a target wiki.
*
* @param sourceWiki the source wiki identifier
* @param targetWiki the target wiki identifier
* @param locale the locale to copy
* @param clean clean the target wiki before copying
* @param context see {@link XWikiContext}
* @return the number of copied documents
* @throws XWikiException failed to copy wiki
* @deprecated since 5.3, use {@link WikiManager#copy(String, String, String, boolean, boolean, boolean)} instead
*/
@Deprecated
public int copyWiki(String sourceWiki, String targetWiki, String locale, boolean clean, XWikiContext context)
throws XWikiException
{
int documents = copySpaceBetweenWikis(null, sourceWiki, targetWiki, locale, clean, context);
ObservationManager om = getObservationManager();
if (om != null) {
om.notify(new WikiCopiedEvent(sourceWiki, targetWiki), sourceWiki, context);
}
return documents;
}
public String getEncoding()
{
return getConfiguration().getProperty("xwiki.encoding", "UTF-8");
}
public URL getServerURL(String database, XWikiContext context) throws MalformedURLException
{
String serverurl = null;
// In virtual wiki path mode the server is the standard one
if ("1".equals(getConfiguration().getProperty("xwiki.virtual.usepath", "1"))) {
return null;
}
if (database != null) {
String db = context.getWikiId();
try {
context.setWikiId(getDatabase());
XWikiDocument doc = getDocument("XWiki.XWikiServer" + StringUtils.capitalize(database), context);
BaseObject serverobject = doc.getXObject(VIRTUAL_WIKI_DEFINITION_CLASS_REFERENCE);
if (serverobject != null) {
String server = serverobject.getStringValue("server");
if (server != null) {
String protocol = getConfiguration().getProperty("xwiki.url.protocol", null);
if (protocol == null) {
int iSecure = serverobject.getIntValue("secure", -1);
// Check the request object if the "secure" property is undefined.
boolean secure = iSecure == 1 || (iSecure < 0 && context.getRequest().isSecure());
protocol = secure ? "https" : "http";
}
long port = context.getURL().getPort();
if (port == 80 || port == 443) {
port = -1;
}
if (port != -1) {
serverurl = protocol + "://" + server + ":" + port + "/";
} else {
serverurl = protocol + "://" + server + "/";
}
}
}
} catch (Exception ex) {
} finally {
context.setWikiId(db);
}
}
if (serverurl != null) {
return new URL(serverurl);
} else {
return null;
}
}
public String getServletPath(String wikiName, XWikiContext context)
{
// unless we are in virtual wiki path mode we should return null
if (!context.getMainXWiki().equalsIgnoreCase(wikiName)
&& "1".equals(getConfiguration().getProperty("xwiki.virtual.usepath", "1"))) {
String database = context.getWikiId();
try {
context.setWikiId(context.getMainXWiki());
XWikiDocument doc = getDocument(getServerWikiPage(wikiName), context);
BaseObject serverobject = doc.getXObject(VIRTUAL_WIKI_DEFINITION_CLASS_REFERENCE);
if (serverobject != null) {
String server = serverobject.getStringValue("server");
return "wiki/" + server + "/";
}
} catch (Exception e) {
LOGGER.error("Failed to get URL for provided wiki [" + wikiName + "]", e);
} finally {
context.setWikiId(database);
}
}
String servletPath = getConfiguration().getProperty("xwiki.servletpath", "");
if (context.getRequest() != null) {
if (StringUtils.isEmpty(servletPath)) {
String currentServletpath = context.getRequest().getServletPath();
if (currentServletpath != null && currentServletpath.startsWith("/bin")) {
servletPath = "bin/";
} else {
servletPath = getConfiguration().getProperty("xwiki.defaultservletpath", "bin/");
}
}
}
return servletPath;
}
public String getWebAppPath(XWikiContext context)
{
String contextPath = getConfiguration().getProperty("xwiki.webapppath");
if (contextPath == null) {
// Try getting the context path by asking the request for it (if a request exists!) and if it doesn't
// work try extracting it from the context URL.
// TODO: Instead of trying to extract from the URL, save the context path at webapp init (using a
// ServlettContextListener for example).
XWikiRequest request = context.getRequest();
if (request != null) {
contextPath = request.getContextPath();
}
if (contextPath == null) {
// Extract the context by getting the first path segment
contextPath = StringUtils.substringBefore(StringUtils.stripStart(context.getURL().getPath(), "/"), "/");
}
}
// Remove any leading or trailing slashes
contextPath = StringUtils.strip(contextPath, "/");
// TODO We're using URL parts in a wrong way, since contextPath and servletPath are returned with a leading /,
// while we need a trailing /. This code ensure we always have CONTEXTNAME + "/".
return contextPath + "/";
}
/**
* @since 7.2M1
*/
public String getURL(EntityReference entityReference, String action, String queryString, String anchor,
XWikiContext context)
{
// TODO: replace this API with a clean implementation of EntityResourceReferenceSerializer
// Handle attachment URL
if (EntityType.ATTACHMENT.equals(entityReference.getType())) {
// Get the full attachment reference
AttachmentReference attachmentReference = getCurrentAttachmentResolver().resolve(entityReference);
return getAttachmentURL(attachmentReference, action, queryString, context);
}
// For all other types, we return the URL of the default corresponding document.
DocumentReference documentReference = getCurrentGetDocumentResolver().resolve(entityReference);
return getURL(documentReference, action, queryString, anchor, context);
}
/**
* @since 7.2M1
*/
public String getURL(EntityReference reference, String action, XWikiContext context)
{
return getURL(reference, action, null, null, context);
}
/**
* @since 7.2RC1
*/
public String getURL(EntityReference reference, XWikiContext context)
{
String action = "view";
if (reference.getType() == EntityType.ATTACHMENT) {
action = "download";
}
return getURL(reference, action, context);
}
/**
* @since 2.2.1
*/
public String getURL(DocumentReference documentReference, String action, String queryString, String anchor,
XWikiContext context)
{
// We need to serialize the space reference because the old createURL() API doesn't accept a DocumentReference.
String spaces = getLocalStringEntityReferenceSerializer().serialize(documentReference.getLastSpaceReference());
// Take into account the specified document locale.
Locale documentLocale = documentReference.getLocale();
String actualQueryString = queryString;
if (documentLocale != null && documentLocale != Locale.ROOT) {
String localeQueryString = "language=" + documentLocale;
if (StringUtils.isEmpty(queryString)) {
actualQueryString = localeQueryString;
} else {
// Note: if the locale is already specified on the given query string then it won't be overwriten
// because the first parameter value is taken into account.
actualQueryString += '&' + localeQueryString;
}
}
URL url = context.getURLFactory().createURL(spaces, documentReference.getName(), action, actualQueryString,
anchor, documentReference.getWikiReference().getName(), context);
return context.getURLFactory().getURL(url, context);
}
/**
* @deprecated since 2.2.1 use {@link #getURL(DocumentReference, String, String, String, XWikiContext)}
*/
@Deprecated
public String getURL(String fullname, String action, String queryString, String anchor, XWikiContext context)
{
return getURL(getCurrentMixedDocumentReferenceResolver().resolve(fullname), action, queryString, anchor,
context);
}
public String getURL(String fullname, String action, String querystring, XWikiContext context)
{
return getURL(fullname, action, querystring, null, context);
}
/**
* @since 2.3M2
*/
public String getURL(DocumentReference reference, String action, XWikiContext context)
{
return getURL(reference, action, null, null, context);
}
/**
* @deprecated since 2.3M2 use {@link #getURL(DocumentReference, String, XWikiContext)}
*/
@Deprecated
public String getURL(String fullname, String action, XWikiContext context)
{
return getURL(fullname, action, null, null, context);
}
public String getExternalURL(String fullname, String action, XWikiContext context) throws XWikiException
{
XWikiDocument doc = new XWikiDocument(getCurrentMixedDocumentReferenceResolver().resolve(fullname));
URL url = context.getURLFactory().createExternalURL(doc.getSpace(), doc.getName(), action, null, null,
doc.getDatabase(), context);
return url.toString();
}
public String getExternalURL(String fullname, String action, String querystring, XWikiContext context)
throws XWikiException
{
XWikiDocument doc = new XWikiDocument(getCurrentMixedDocumentReferenceResolver().resolve(fullname));
URL url = context.getURLFactory().createExternalURL(doc.getSpace(), doc.getName(), action, querystring, null,
doc.getDatabase(), context);
return url.toString();
}
/**
* @since 7.2M1
*/
public String getAttachmentURL(AttachmentReference attachmentReference, String action, String queryString,
XWikiContext context)
{
DocumentReference documentReference = attachmentReference.getDocumentReference();
SpaceReference spaceReference = documentReference.getLastSpaceReference();
WikiReference wikiReference = spaceReference.getWikiReference();
// We need to serialize the space reference because the old URLFactory has no method to create an Attachment URL
// from an AttachmentReference...
String serializedSpace = getLocalStringEntityReferenceSerializer().serialize(spaceReference);
URL url = context.getURLFactory().createAttachmentURL(attachmentReference.getName(), serializedSpace,
documentReference.getName(), action, queryString, wikiReference.getName(), context);
return context.getURLFactory().getURL(url, context);
}
/**
* @since 7.2M1
*/
public String getAttachmentURL(AttachmentReference attachmentReference, String queryString, XWikiContext context)
{
return getAttachmentURL(attachmentReference, "download", queryString, context);
}
/**
* @since 7.2M1
*/
public String getAttachmentRevisionURL(AttachmentReference attachmentReference, String revision, String queryString,
XWikiContext context)
{
DocumentReference documentReference = attachmentReference.getDocumentReference();
SpaceReference spaceReference = documentReference.getLastSpaceReference();
WikiReference wikiReference = spaceReference.getWikiReference();
// We need to serialize the space reference because the old URLFactory has no method to create an Attachment URL
// from an AttachmentReference...
String serializedSpace = getLocalStringEntityReferenceSerializer().serialize(spaceReference);
URL url = context.getURLFactory().createAttachmentRevisionURL(attachmentReference.getName(), serializedSpace,
documentReference.getName(), revision, queryString, wikiReference.getName(), context);
return context.getURLFactory().getURL(url, context);
}
public String getAttachmentURL(String fullname, String filename, XWikiContext context) throws XWikiException
{
return getAttachmentURL(fullname, filename, null, context);
}
/**
* @since 2.5RC1
*/
public String getAttachmentURL(String fullname, String filename, String queryString, XWikiContext context)
throws XWikiException
{
AttachmentReference attachmentReference =
new AttachmentReference(filename, getCurrentMixedDocumentReferenceResolver().resolve(fullname));
return getAttachmentURL(attachmentReference, queryString, context);
}
// Usefull date functions
public int getTimeDelta(long time)
{
Date ctime = new Date();
return (int) (ctime.getTime() - time);
}
public boolean isMultiLingual(XWikiContext context)
{
return "1".equals(getXWikiPreference("multilingual", "0", context));
}
public boolean isLDAP()
{
return "1".equals(getConfiguration().getProperty("xwiki.authentication.ldap"));
}
/**
* @return true if XWikiAllGroup group should be seen as virtual group containing all users, false to use it as any
* other group
* @since 9.3RC1
*/
public boolean isAllGroupImplicit()
{
return "1".equals(getConfiguration().getProperty("xwiki.authentication.group.allgroupimplicit"));
}
public int checkActive(XWikiContext context) throws XWikiException
{
return checkActive(context.getUser(), context);
}
public int checkActive(String user, XWikiContext context) throws XWikiException
{
int active = 1;
// These users are necessarily active
if (user.equals(XWikiRightService.GUEST_USER_FULLNAME)
|| (user.equals(XWikiRightService.SUPERADMIN_USER_FULLNAME))) {
return active;
}
String checkactivefield = getXWikiPreference("auth_active_check", context);
if (checkactivefield.equals("1")) {
XWikiDocument userdoc = getDocument(user, context);
active = userdoc.getIntValue("XWiki.XWikiUsers", "active");
}
return active;
}
/**
* @since 2.3M1
*/
public DocumentReference getDocumentReference(XWikiRequest request, XWikiContext context)
{
DocumentReference reference;
if (context.getMode() == XWikiContext.MODE_PORTLET) {
if (request.getParameter("topic") != null) {
reference = getCurrentMixedDocumentReferenceResolver().resolve(request.getParameter("topic"));
} else {
// Point to this wiki's home page
reference = getDefaultDocumentReference().setWikiReference(new WikiReference(context.getWikiId()));
}
} else if (context.getMode() == XWikiContext.MODE_XMLRPC) {
reference = new DocumentReference(context.getWikiId(),
context.getDoc().getDocumentReference().getLastSpaceReference().getName(),
context.getDoc().getDocumentReference().getName());
} else {
ResourceReference resourceReference = getResourceReferenceManager().getResourceReference();
if (resourceReference instanceof EntityResourceReference) {
EntityResourceReference entityResource = (EntityResourceReference) resourceReference;
String action = entityResource.getAction().getActionName();
if ((request.getParameter("topic") != null) && (action.equals("edit") || action.equals("inline"))) {
reference = getCurrentMixedDocumentReferenceResolver().resolve(request.getParameter("topic"));
} else {
reference = new DocumentReference(
entityResource.getEntityReference().extractReference(EntityType.DOCUMENT));
}
} else {
// TODO: Handle references not pointing to a document...
// Big problem we don't have an Entity URL!
throw new RuntimeException(
String.format("Resource Reference [%s] isn't an Entity Resource Reference!", resourceReference));
}
}
return reference;
}
/**
* Helper method, removes a predefined path segment (the context path or the servel path) from the start of the
* requested URI and returns the remainder. This method is needed because special characters in the path can be
* URL-encoded, depending on whether the request is forwarded through the request dispatcher or not, and also
* depending on the client (some browsers encode -, while some don't).
*
* @param path the path, as taken from the requested URI
* @param segment the segment to remove, as reported by the container
* @return the path with the specified segment trimmed from its start
*/
public static String stripSegmentFromPath(String path, String segment)
{
if (!path.startsWith(segment)) {
// The context path probably contains special characters that are encoded in the URL
try {
segment = URIUtil.encodePath(segment);
} catch (URIException e) {
LOGGER.warn("Invalid path: [" + segment + "]");
}
}
if (!path.startsWith(segment)) {
// Some clients also encode -, although it's allowed in the path
segment = segment.replaceAll("-", "%2D");
}
if (!path.startsWith(segment)) {
// Can't find the context path in the URL (shouldn't happen), just skip to the next path segment
return path.substring(path.indexOf('/', 1));
}
return path.substring(segment.length());
}
public boolean prepareDocuments(XWikiRequest request, XWikiContext context, VelocityContext vcontext)
throws XWikiException
{
XWikiDocument doc;
context.getWiki().prepareResources(context);
DocumentReference reference = getDocumentReference(request, context);
if (context.getAction().equals("register")) {
setPhonyDocument(reference, context, vcontext);
doc = context.getDoc();
} else {
try {
doc = getDocument(reference, context);
} catch (XWikiException e) {
doc = context.getDoc();
if (context.getAction().equals("delete")) {
if (doc == null) {
setPhonyDocument(reference, context, vcontext);
doc = context.getDoc();
}
if (!checkAccess("admin", doc, context)) {
throw e;
}
} else {
throw e;
}
}
}
// We need to check rights before we look for translations
// Otherwise we don't have the user language
if (checkAccess(context.getAction(), doc, context) == false) {
Object[] args = { doc.getFullName(), context.getUser() };
setPhonyDocument(reference, context, vcontext);
throw new XWikiException(XWikiException.MODULE_XWIKI_ACCESS, XWikiException.ERROR_XWIKI_ACCESS_DENIED,
"Access to document {0} has been denied to user {1}", null, args);
} else if (checkActive(context) == 0) { // if auth_active_check, check if user is inactive
boolean allow = false;
String action = context.getAction();
/*
* Allow inactive users to see skins, ressources, SSX, JSX and downloads they could have seen as guest. The
* rational behind this behaviour is that inactive users should be able to access the same UI that guests
* are used to see, including custom icons, panels, and so on...
*/
if ((action.equals("skin") && (doc.getSpace().equals("skins") || doc.getSpace().equals("resources")))
|| ((action.equals("skin") || action.equals("download") || action.equals("ssx") || action.equals("jsx"))
&& getRightService().hasAccessLevel("view", XWikiRightService.GUEST_USER_FULLNAME,
doc.getPrefixedFullName(), context))
|| ((action.equals("view") && doc.getFullName().equals("XWiki.AccountValidation")))) {
allow = true;
} else {
String allowed = getConfiguration().getProperty("xwiki.inactiveuser.allowedpages", "");
if (context.getAction().equals("view") && !allowed.equals("")) {
String[] allowedList = StringUtils.split(allowed, " ,");
for (String element : allowedList) {
if (element.equals(doc.getFullName())) {
allow = true;
break;
}
}
}
}
if (!allow) {
Object[] args = { context.getUser() };
setPhonyDocument(reference, context, vcontext);
throw new XWikiException(XWikiException.MODULE_XWIKI_USER, XWikiException.ERROR_XWIKI_USER_INACTIVE,
"User {0} account is inactive", null, args);
}
}
context.put("doc", doc);
context.put("cdoc", doc);
vcontext.put("doc", doc.newDocument(context));
vcontext.put("cdoc", vcontext.get("doc"));
XWikiDocument tdoc = doc.getTranslatedDocument(context);
try {
String rev = (String) context.get("rev");
if (StringUtils.isNotEmpty(rev)) {
tdoc = getDocument(tdoc, rev, context);
}
} catch (Exception ex) {
// Invalid version, just use the most recent one
}
context.put("tdoc", tdoc);
vcontext.put("tdoc", tdoc.newDocument(context));
return true;
}
/**
* @since 8.3M1
*/
public void setPhonyDocument(DocumentReference reference, XWikiContext context)
{
XWikiDocument doc = new XWikiDocument(reference);
doc.setElements(XWikiDocument.HAS_ATTACHMENTS | XWikiDocument.HAS_OBJECTS);
doc.setStore(getStore());
context.put("doc", doc);
}
/**
* @since 2.3M1
* @deprecated since 8.3M1, use {@link #setPhonyDocument(DocumentReference, XWikiContext)} instead
*/
@Deprecated
public void setPhonyDocument(DocumentReference reference, XWikiContext context, VelocityContext vcontext)
{
setPhonyDocument(reference, context);
vcontext.put("doc", context.getDoc().newDocument(context));
vcontext.put("cdoc", vcontext.get("doc"));
vcontext.put("tdoc", vcontext.get("doc"));
}
/**
* @deprecated since 2.3M1 use {@link #setPhonyDocument(DocumentReference, XWikiContext, VelocityContext)}
*/
@Deprecated
public void setPhonyDocument(String docName, XWikiContext context, VelocityContext vcontext)
{
setPhonyDocument(getCurrentMixedDocumentReferenceResolver().resolve(docName), context, vcontext);
}
public XWikiEngineContext getEngineContext()
{
return this.engine_context;
}
public void setEngineContext(XWikiEngineContext engine_context)
{
this.engine_context = engine_context;
}
public void setAuthService(XWikiAuthService authService)
{
this.authService = authService;
}
public void setRightService(XWikiRightService rightService)
{
this.rightService = rightService;
}
public XWikiGroupService getGroupService(XWikiContext context) throws XWikiException
{
synchronized (this.GROUP_SERVICE_LOCK) {
if (this.groupService == null) {
String groupClass = getConfiguration().getProperty("xwiki.authentication.groupclass",
"com.xpn.xwiki.user.impl.xwiki.XWikiGroupServiceImpl");
try {
this.groupService = (XWikiGroupService) Class.forName(groupClass).newInstance();
} catch (Exception e) {
LOGGER.error("Failed to instantiate custom group service class: " + e.getMessage(), e);
this.groupService = new XWikiGroupServiceImpl();
}
this.groupService.init(this, context);
}
return this.groupService;
}
}
public void setGroupService(XWikiGroupService groupService)
{
this.groupService = groupService;
}
// added some log statements to make debugging easier - LBlaze 2005.06.02
public XWikiAuthService getAuthService()
{
synchronized (this.AUTH_SERVICE_LOCK) {
if (this.authService == null) {
LOGGER.info("Initializing AuthService...");
String authClass = getConfiguration().getProperty("xwiki.authentication.authclass");
if (StringUtils.isNotEmpty(authClass)) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Using custom AuthClass " + authClass + ".");
}
} else {
if (isLDAP()) {
authClass = "com.xpn.xwiki.user.impl.LDAP.XWikiLDAPAuthServiceImpl";
} else {
authClass = "com.xpn.xwiki.user.impl.xwiki.XWikiAuthServiceImpl";
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Using default AuthClass " + authClass + ".");
}
}
try {
// Get the current ClassLoader
@SuppressWarnings("deprecation")
ClassLoaderManager clManager = Utils.getComponent(ClassLoaderManager.class);
ClassLoader classloader = null;
if (clManager != null) {
classloader = clManager.getURLClassLoader("wiki:xwiki", false);
}
// Get the class
if (classloader != null) {
this.authService = (XWikiAuthService) Class.forName(authClass, true, classloader).newInstance();
} else {
this.authService = (XWikiAuthService) Class.forName(authClass).newInstance();
}
LOGGER.debug("Initialized AuthService using Relfection.");
} catch (Exception e) {
LOGGER.warn("Failed to initialize AuthService " + authClass
+ " using Reflection, trying default implementations using 'new'.", e);
this.authService = new XWikiAuthServiceImpl();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(
"Initialized AuthService " + this.authService.getClass().getName() + " using 'new'.");
}
}
}
return this.authService;
}
}
private static final String DEFAULT_RIGHT_SERVICE_CLASS =
"org.xwiki.security.authorization.internal.XWikiCachingRightService";
public XWikiRightService getRightService()
{
synchronized (this.RIGHT_SERVICE_LOCK) {
if (this.rightService == null) {
LOGGER.info("Initializing RightService...");
String rightsClass = getConfiguration().getProperty("xwiki.authentication.rightsclass");
if (rightsClass != null && !rightsClass.equals(DEFAULT_RIGHT_SERVICE_CLASS)) {
if (LOGGER.isDebugEnabled()) {
LOGGER.warn("Using custom Right Service [{}].", rightsClass);
}
} else {
rightsClass = DEFAULT_RIGHT_SERVICE_CLASS;
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Using default Right Service [{}].", rightsClass);
}
}
try {
this.rightService = (XWikiRightService) Class.forName(rightsClass).newInstance();
LOGGER.debug("Initialized RightService using Reflection.");
} catch (Exception e) {
Exception lastException = e;
if (!rightsClass.equals(DEFAULT_RIGHT_SERVICE_CLASS)) {
LOGGER.warn(String.format(
"Failed to initialize custom RightService [%s]"
+ " by Reflection, using default implementation [%s].",
rightsClass, DEFAULT_RIGHT_SERVICE_CLASS), e);
rightsClass = DEFAULT_RIGHT_SERVICE_CLASS;
try {
this.rightService = (XWikiRightService) Class.forName(rightsClass).newInstance();
LOGGER.debug("Initialized default RightService using Reflection.");
} catch (Exception e1) {
lastException = e1;
}
}
if (this.rightService == null) {
LOGGER.warn(String.format(
"Failed to initialize RightService [%s]"
+ " by Reflection, using OLD implementation [%s] with 'new'.",
rightsClass, XWikiRightServiceImpl.class.getCanonicalName()), lastException);
this.rightService = new XWikiRightServiceImpl();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Initialized old RightService implementation "
+ this.rightService.getClass().getName() + " using 'new'.");
}
}
}
}
return this.rightService;
}
}
public XWikiStatsService getStatsService(XWikiContext context)
{
synchronized (this.STATS_SERVICE_LOCK) {
if (this.statsService == null) {
if ("1".equals(getConfiguration().getProperty("xwiki.stats", "1"))) {
String storeClass = getConfiguration().getProperty("xwiki.stats.class",
"com.xpn.xwiki.stats.impl.XWikiStatsServiceImpl");
try {
this.statsService = (XWikiStatsService) Class.forName(storeClass).newInstance();
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
this.statsService = new XWikiStatsServiceImpl();
}
this.statsService.init(context);
}
}
return this.statsService;
}
}
public XWikiURLFactoryService getURLFactoryService()
{
if (this.urlFactoryService == null) {
synchronized (this.URLFACTORY_SERVICE_LOCK) {
if (this.urlFactoryService == null) {
LOGGER.info("Initializing URLFactory Service...");
XWikiURLFactoryService factoryService = null;
String urlFactoryServiceClass = getConfiguration().getProperty("xwiki.urlfactory.serviceclass");
if (urlFactoryServiceClass != null) {
try {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Using custom URLFactory Service Class [" + urlFactoryServiceClass + "]");
}
factoryService = (XWikiURLFactoryService) Class.forName(urlFactoryServiceClass)
.getConstructor(new Class<?>[] { XWiki.class }).newInstance(new Object[] { this });
} catch (Exception e) {
factoryService = null;
LOGGER.warn("Failed to initialize URLFactory Service [" + urlFactoryServiceClass + "]", e);
}
}
if (factoryService == null) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Using default URLFactory Service Class [" + urlFactoryServiceClass + "]");
}
factoryService = new XWikiURLFactoryServiceImpl(this);
}
// Set the urlFactoryService object in one assignment to prevent threading
// issues when checking for
// null above.
this.urlFactoryService = factoryService;
}
}
}
return this.urlFactoryService;
}
public XWikiCriteriaService getCriteriaService(XWikiContext context)
{
return this.criteriaService;
}
public ZipOutputStream getZipOutputStream(XWikiContext context) throws IOException
{
return new ZipOutputStream(context.getResponse().getOutputStream());
}
private Map<String, SearchEngineRule> getSearchEngineRules(XWikiContext context)
{
// We currently hardcode the rules
// We will put them in the preferences soon
Map<String, SearchEngineRule> map = new HashMap<String, SearchEngineRule>();
map.put("Google", new SearchEngineRule("google.", "s/(^|.*&)q=(.*?)(&.*|$)/$2/"));
map.put("MSN", new SearchEngineRule("search.msn.", "s/(^|.*&)q=(.*?)(&.*|$)/$2/"));
map.put("Yahoo", new SearchEngineRule("search.yahoo.", "s/(^|.*&)p=(.*?)(&.*|$)/$2/"));
map.put("Voila", new SearchEngineRule("voila.fr", "s/(^|.*&)kw=(.*?)(&.*|$)/$2/"));
return map;
}
public String getRefererText(String referer, XWikiContext context)
{
try {
URL url = new URL(referer);
Map<String, SearchEngineRule> searchengines = getSearchEngineRules(context);
if (searchengines != null) {
for (SearchEngineRule senginerule : searchengines.values()) {
String host = url.getHost();
int i1 = host.indexOf(senginerule.getHost());
if (i1 != -1) {
String query = context.getUtil().substitute(senginerule.getRegEx(), url.getQuery());
if ((query != null) && (!query.equals(""))) {
// We return the query text instead of the full referer
return host.substring(i1) + ":" + query;
}
}
}
}
} catch (Exception e) {
}
String result = referer.substring(referer.indexOf("://") + 3);
if (result.endsWith("/")) {
return result.substring(0, result.length() - 1);
} else {
return result;
}
}
public boolean isMySQL()
{
if (getHibernateStore() == null) {
return false;
}
Object dialect = getHibernateStore().getConfiguration().getProperties().get("dialect");
return "org.hibernate.dialect.MySQLDialect".equals(dialect)
|| "net.sf.hibernate.dialect.MySQLDialect".equals(dialect);
}
public String getFullNameSQL()
{
return getFullNameSQL(true);
}
public String getFullNameSQL(boolean newFullName)
{
if (newFullName) {
return "doc.fullName";
}
if (this.fullNameSQL == null) {
if (isMySQL()) {
this.fullNameSQL = "CONCAT(doc.space,'.',doc.name)";
} else {
this.fullNameSQL = "doc.space||'.'||doc.name";
}
}
return this.fullNameSQL;
}
public String getUserName(String user, XWikiContext context)
{
return getUserName(user, null, true, context);
}
public String getUserName(String user, String format, XWikiContext context)
{
return getUserName(user, format, true, context);
}
/**
* @return a formatted and pretty printed user name for displaying
*/
public String getUserName(String user, String format, boolean link, XWikiContext context)
{
if (StringUtils.isBlank(user)) {
return localizePlainOrKey("core.users.unknownUser");
}
DocumentReference userReference = getCurrentMixedDocumentReferenceResolver().resolve(user);
return getUserName(userReference, format, link, true, context);
}
/**
* Generate a display user name and return it.
*
* @param userReference
* @param format a Velocity scnippet used to format the user name
* @param link true if a full html link snippet should be returned
* @param escapeXML true if the returned name should be escaped (forced true if {@code link} is true)
* @param context see {@link XWikiContext}
* @return the display user name or a html snippet with the link to the passed user
* @since 6.4RC1
*/
public String getUserName(DocumentReference userReference, String format, boolean link, boolean escapeXML,
XWikiContext context)
{
if (userReference == null) {
return localizePlainOrKey("core.users.unknownUser");
}
XWikiDocument userdoc = null;
try {
userdoc = getDocument(userReference, context);
if (userdoc == null) {
return escapeXML ? XMLUtils.escape(userReference.getName()) : userReference.getName();
}
BaseObject userobj = userdoc.getObject("XWiki.XWikiUsers");
if (userobj == null) {
return escapeXML ? XMLUtils.escape(userdoc.getDocumentReference().getName())
: userdoc.getDocumentReference().getName();
}
String text;
if (format == null) {
text = userobj.getStringValue("first_name");
String lastName = userobj.getStringValue("last_name");
if (!text.isEmpty() && !lastName.isEmpty()) {
text += ' ';
}
text += userobj.getStringValue("last_name");
if (StringUtils.isBlank(text)) {
text = userdoc.getDocumentReference().getName();
}
} else {
VelocityContext vcontext = new VelocityContext();
for (String propname : userobj.getPropertyList()) {
vcontext.put(propname, userobj.getStringValue(propname));
}
text = evaluateVelocity(format,
"<username formatting code in " + context.getDoc().getDocumentReference() + ">", vcontext);
}
if (escapeXML || link) {
text = XMLUtils.escape(text.trim());
}
if (link) {
text = "<span class=\"wikilink\"><a href=\"" + userdoc.getURL("view", context) + "\">" + text
+ "</a></span>";
}
return text;
} catch (Exception e) {
LOGGER.warn("Failed to display the user name of [{}]. Root cause is [{}]. Falling back on the user id.",
userReference, ExceptionUtils.getRootCauseMessage(e));
return escapeXML ? XMLUtils.escape(userReference.getName()) : userReference.getName();
}
}
/**
* @param content the Velocity content to evaluate
* @param namespace the namespace under which to evaluate it (used for isolation)
* @param vcontext the Velocity context to use when evaluating. If {@code null}, then a new context will be created,
* initialized and used.
* @return the evaluated content
* @since 7.2M1
*/
public String evaluateVelocity(String content, String namespace, VelocityContext vcontext)
{
StringWriter writer = new StringWriter();
boolean renderingContextPushed = false;
try {
// Switch current namespace if needed
String currentNamespace = getRenderingContext().getTransformationId();
if (namespace != null && !StringUtils.equals(namespace, currentNamespace)) {
if (getRenderingContext() instanceof MutableRenderingContext) {
// Make the current velocity template id available
((MutableRenderingContext) getRenderingContext()).push(getRenderingContext().getTransformation(),
getRenderingContext().getXDOM(), getRenderingContext().getDefaultSyntax(), namespace,
getRenderingContext().isRestricted(), getRenderingContext().getTargetSyntax());
renderingContextPushed = true;
}
}
VelocityManager velocityManager = Utils.getComponent(VelocityManager.class);
velocityManager.getVelocityEngine().evaluate(vcontext, writer, namespace, content);
return writer.toString();
} catch (Exception e) {
LOGGER.error("Error while parsing velocity template namespace [{}] with content:\n[{}]", namespace, content,
e);
Object[] args = { namespace };
XWikiException xe = new XWikiException(XWikiException.MODULE_XWIKI_RENDERING,
XWikiException.ERROR_XWIKI_RENDERING_VELOCITY_EXCEPTION, "Error while parsing velocity page {0}", e,
args);
return Util.getHTMLExceptionMessage(xe, null);
} finally {
// Get rid of temporary rendering context
if (renderingContextPushed) {
((MutableRenderingContext) this.renderingContext).pop();
}
}
}
/**
* @param content the Velocity content to evaluate
* @param name the namespace under which to evaluate it (used for isolation)
* @return the evaluated content
* @since 7.2M1
*/
public String evaluateVelocity(String content, String name)
{
try {
VelocityManager velocityManager = Utils.getComponent(VelocityManager.class);
VelocityContext velocityContext = velocityManager.getVelocityContext();
return evaluateVelocity(content, name, velocityContext);
} catch (Exception e) {
LOGGER.error("Error while parsing velocity template namespace [{}] with content:\n[{}]", name, content, e);
Object[] args = { name };
XWikiException xe = new XWikiException(XWikiException.MODULE_XWIKI_RENDERING,
XWikiException.ERROR_XWIKI_RENDERING_VELOCITY_EXCEPTION, "Error while parsing velocity page {0}", e,
args);
return Util.getHTMLExceptionMessage(xe, null);
}
}
/**
* Generate and return an unescaped user display name.
*
* @param userReference the user reference
* @param context see {@link XWikiContext}
* @return the unescaped display user name
* @since 6.4RC1
*/
public String getPlainUserName(DocumentReference userReference, XWikiContext context)
{
return getUserName(userReference, null, false, false, context);
}
public boolean hasCentralizedAuthentication(XWikiContext context)
{
String bl = getXWikiPreference("authentication_centralized", "", context);
if ("1".equals(bl)) {
return true;
}
if ("0".equals(bl)) {
return false;
}
return "1".equals(getConfiguration().getProperty("xwiki.authentication.centralized", "0"));
}
public String getLocalUserName(String user, XWikiContext context)
{
if (hasCentralizedAuthentication(context)) {
return getUserName(user, null, true, context);
} else {
return getUserName(user.substring(user.indexOf(':') + 1), null, true, context);
}
}
public String getLocalUserName(String user, String format, XWikiContext context)
{
if (hasCentralizedAuthentication(context)) {
return getUserName(user, format, true, context);
} else {
return getUserName(user.substring(user.indexOf(':') + 1), format, true, context);
}
}
public String getLocalUserName(String user, String format, boolean link, XWikiContext context)
{
if (hasCentralizedAuthentication(context)) {
return getUserName(user, format, link, context);
} else {
return getUserName(user.substring(user.indexOf(':') + 1), format, link, context);
}
}
public String formatDate(Date date, String format, XWikiContext context)
{
if (date == null) {
return "";
}
String xformat = format;
String defaultFormat = "yyyy/MM/dd HH:mm";
if (format == null) {
xformat = getXWikiPreference("dateformat", defaultFormat, context);
}
try {
DateFormatSymbols formatSymbols = null;
try {
String language = getLanguagePreference(context);
formatSymbols = new DateFormatSymbols(new Locale(language));
} catch (Exception e2) {
String language = getXWikiPreference("default_language", context);
if ((language != null) && (!language.equals(""))) {
formatSymbols = new DateFormatSymbols(new Locale(language));
}
}
SimpleDateFormat sdf;
if (formatSymbols != null) {
sdf = new SimpleDateFormat(xformat, formatSymbols);
} else {
sdf = new SimpleDateFormat(xformat);
}
try {
sdf.setTimeZone(TimeZone.getTimeZone(getUserTimeZone(context)));
} catch (Exception e) {
}
return sdf.format(date);
} catch (Exception e) {
LOGGER.info("Failed to format date [" + date + "] with pattern [" + xformat + "]: " + e.getMessage());
if (format == null) {
if (xformat.equals(defaultFormat)) {
return date.toString();
} else {
return formatDate(date, defaultFormat, context);
}
} else {
return formatDate(date, null, context);
}
}
}
/*
* Allow to read user setting providing the user timezone All dates will be expressed with this timezone
*/
public String getUserTimeZone(XWikiContext context)
{
String tz = getUserPreference("timezone", context);
// We perform this verification ourselves since TimeZone#getTimeZone(String) with an invalid parameter returns
// GMT and not the system default.
if (!ArrayUtils.contains(TimeZone.getAvailableIDs(), tz)) {
String defaultTz = TimeZone.getDefault().getID();
return getConfiguration().getProperty("xwiki.timezone", defaultTz);
} else {
return tz;
}
}
/**
* @deprecated since 2.2.1 use {@link #exists(DocumentReference, XWikiContext)}
*/
@Deprecated
public boolean exists(String fullname, XWikiContext context)
{
return exists(getCurrentMixedDocumentReferenceResolver().resolve(fullname), context);
}
public boolean exists(DocumentReference documentReference, XWikiContext context)
{
String currentWiki = context.getWikiId();
try {
XWikiDocument doc = new XWikiDocument(documentReference, documentReference.getLocale());
context.setWikiId(documentReference.getWikiReference().getName());
return getStore().exists(doc, context);
} catch (XWikiException e) {
return false;
} finally {
context.setWikiId(currentWiki);
}
}
public String getAdType(XWikiContext context)
{
String adtype = "";
XWikiDocument wikiServer = context.getWikiServer();
if (wikiServer != null) {
adtype = wikiServer.getStringValue(VIRTUAL_WIKI_DEFINITION_CLASS_REFERENCE, "adtype");
}
if (adtype.equals("")) {
adtype = getConfiguration().getProperty("xwiki.ad.type", "");
}
return adtype;
}
public String getAdClientId(XWikiContext context)
{
final String defaultadclientid = "pub-2778691407285481";
String adclientid = "";
XWikiDocument wikiServer = context.getWikiServer();
if (wikiServer != null) {
adclientid = wikiServer.getStringValue(VIRTUAL_WIKI_DEFINITION_CLASS_REFERENCE, "adclientid");
}
if (adclientid.equals("")) {
adclientid = getConfiguration().getProperty("xwiki.ad.clientid", "");
}
if (adclientid.equals("")) {
adclientid = defaultadclientid;
}
return adclientid;
}
@Deprecated
public XWikiPluginInterface getPlugin(String name, XWikiContext context)
{
XWikiPluginManager plugins = getPluginManager();
Vector<String> pluginlist = plugins.getPlugins();
for (String pluginname : pluginlist) {
if (pluginname.equals(name)) {
return plugins.getPlugin(pluginname);
}
}
return null;
}
@Deprecated
public Api getPluginApi(String name, XWikiContext context)
{
XWikiPluginInterface plugin = getPlugin(name, context);
if (plugin != null) {
return plugin.getPluginApi(plugin, context);
}
return null;
}
public int getHttpTimeout(XWikiContext context)
{
return getConfiguration().getProperty("xwiki.http.timeout", 60000);
}
public String getHttpUserAgent(XWikiContext context)
{
return getConfiguration().getProperty("xwiki.http.useragent", "XWikiBot/1.0");
}
public String getURLContent(String surl, XWikiContext context) throws IOException
{
return getURLContent(surl, getHttpTimeout(context), getHttpUserAgent(context));
}
public String getURLContent(String surl, int timeout, String userAgent) throws IOException
{
String content;
HttpClient client = getHttpClient(timeout, userAgent);
GetMethod get = new GetMethod(surl);
try {
client.executeMethod(get);
content = get.getResponseBodyAsString();
} finally {
// Release any connection resources used by the method
get.releaseConnection();
}
return content;
}
public String getURLContent(String surl, String username, String password, XWikiContext context) throws IOException
{
return getURLContent(surl, username, password, getHttpTimeout(context), getHttpUserAgent(context));
}
public String getURLContent(String surl, String username, String password, int timeout, String userAgent)
throws IOException
{
HttpClient client = getHttpClient(timeout, userAgent);
// pass our credentials to HttpClient, they will only be used for
// authenticating to servers with realm "realm", to authenticate agains
// an arbitrary realm change this to null.
client.getState().setCredentials(new AuthScope(null, -1, null),
new UsernamePasswordCredentials(username, password));
// create a GET method that reads a file over HTTPS, we're assuming
// that this file requires basic authentication using the realm above.
GetMethod get = new GetMethod(surl);
try {
// Tell the GET method to automatically handle authentication. The
// method will use any appropriate credentials to handle basic
// authentication requests. Setting this value to false will cause
// any request for authentication to return with a status of 401.
// It will then be up to the client to handle the authentication.
get.setDoAuthentication(true);
// execute the GET
client.executeMethod(get);
// print the status and response
return get.getResponseBodyAsString();
} finally {
// release any connection resources used by the method
get.releaseConnection();
}
}
public byte[] getURLContentAsBytes(String surl, XWikiContext context) throws IOException
{
return getURLContentAsBytes(surl, getHttpTimeout(context), getHttpUserAgent(context));
}
public byte[] getURLContentAsBytes(String surl, int timeout, String userAgent) throws IOException
{
HttpClient client = getHttpClient(timeout, userAgent);
// create a GET method that reads a file over HTTPS, we're assuming
// that this file requires basic authentication using the realm above.
GetMethod get = new GetMethod(surl);
try {
// execute the GET
client.executeMethod(get);
// print the status and response
return get.getResponseBody();
} finally {
// release any connection resources used by the method
get.releaseConnection();
}
}
public byte[] getURLContentAsBytes(String surl, String username, String password, XWikiContext context)
throws IOException
{
return getURLContentAsBytes(surl, username, password, getHttpTimeout(context), getHttpUserAgent(context));
}
public byte[] getURLContentAsBytes(String surl, String username, String password, int timeout, String userAgent)
throws IOException
{
HttpClient client = getHttpClient(timeout, userAgent);
// pass our credentials to HttpClient, they will only be used for
// authenticating to servers with realm "realm", to authenticate agains
// an arbitrary realm change this to null.
client.getState().setCredentials(new AuthScope(null, -1, null),
new UsernamePasswordCredentials(username, password));
// create a GET method that reads a file over HTTPS, we're assuming
// that this file requires basic authentication using the realm above.
GetMethod get = new GetMethod(surl);
try {
// Tell the GET method to automatically handle authentication. The
// method will use any appropriate credentials to handle basic
// authentication requests. Setting this value to false will cause
// any request for authentication to return with a status of 401.
// It will then be up to the client to handle the authentication.
get.setDoAuthentication(true);
// execute the GET
client.executeMethod(get);
// print the status and response
return get.getResponseBody();
} finally {
// release any connection resources used by the method
get.releaseConnection();
}
}
/**
* API to list all spaces in the current wiki.
* <p>
* Hidden spaces are filtered unless current user enabled them.
*
* @return a list of string representing all non-hidden spaces (ie spaces that have non-hidden pages) for the
* current wiki
* @throws XWikiException if something went wrong
* @deprecated use query service instead
*/
@Deprecated
public List<String> getSpaces(XWikiContext context) throws XWikiException
{
try {
return getStore().getQueryManager().getNamedQuery("getSpaces")
.addFilter(Utils.<QueryFilter>getComponent(QueryFilter.class, "hidden")).execute();
} catch (QueryException ex) {
throw new XWikiException(0, 0, ex.getMessage(), ex);
}
}
/**
* API to list all non-hidden documents in a space.
*
* @param spaceReference the local reference of the space for which to return all non-hidden documents
* @return the list of document names (in the format {@code Space.Page}) for non-hidden documents in the specified
* space
* @throws XWikiException if the loading went wrong
* @deprecated use query service instead
*/
@Deprecated
public List<String> getSpaceDocsName(String spaceReference, XWikiContext context) throws XWikiException
{
try {
return getStore().getQueryManager().getNamedQuery("getSpaceDocsName")
.addFilter(Utils.<QueryFilter>getComponent(QueryFilter.class, "hidden"))
.bindValue("space", spaceReference).execute();
} catch (QueryException ex) {
throw new XWikiException(0, 0, ex.getMessage(), ex);
}
}
public List<String> getIncludedMacros(String defaultSpace, String content, XWikiContext context)
{
List<String> list;
try {
String pattern = "#includeMacros[ ]*\\([ ]*([\"'])(.*?)\\1[ ]*\\)";
list = context.getUtil().getUniqueMatches(content, pattern, 2);
for (int i = 0; i < list.size(); i++) {
String name = list.get(i);
if (name.indexOf('.') == -1) {
list.set(i, defaultSpace + "." + name);
}
}
} catch (Exception e) {
// This should never happen
LOGGER.error("Failed to extract #includeMacros targets from provided content [" + content + "]", e);
list = Collections.emptyList();
}
return list;
}
/**
* accessor for the isReadOnly instance var.
*
* @see #isReadOnly
*/
public boolean isReadOnly()
{
return this.isReadOnly;
}
public void setReadOnly(boolean readOnly)
{
this.isReadOnly = readOnly;
}
public void deleteAllDocuments(XWikiDocument doc, XWikiContext context) throws XWikiException
{
deleteAllDocuments(doc, true, context);
}
public void deleteAllDocuments(XWikiDocument doc, boolean toTrash, XWikiContext context) throws XWikiException
{
// Delete all translation documents
for (Locale locale : doc.getTranslationLocales(context)) {
XWikiDocument tdoc = doc.getTranslatedDocument(locale, context);
deleteDocument(tdoc, toTrash, context);
}
// Delete the default document
deleteDocument(doc, toTrash, context);
}
public void refreshLinks(XWikiContext context) throws XWikiException
{
try {
// refreshes all Links of each doc of the wiki
@SuppressWarnings("deprecation")
List<String> docs = getStore().getQueryManager().getNamedQuery("getAllDocuments")
.addFilter(Utils.<QueryFilter>getComponent(QueryFilter.class, "hidden")).execute();
for (int i = 0; i < docs.size(); i++) {
XWikiDocument myDoc = this.getDocument(docs.get(i), context);
myDoc.getStore().saveLinks(myDoc, context, true);
}
} catch (QueryException ex) {
throw new XWikiException(0, 0, ex.getMessage(), ex);
}
}
public boolean hasBacklinks(XWikiContext context)
{
if (this.hasBacklinks == null) {
this.hasBacklinks = "1".equals(getXWikiPreference("backlinks", "xwiki.backlinks", "0", context));
}
return this.hasBacklinks;
}
public boolean hasTags(XWikiContext context)
{
return "1".equals(getXWikiPreference("tags", "xwiki.tags", "0", context));
}
public boolean hasCustomMappings()
{
return "1".equals(getConfiguration().getProperty("xwiki.store.hibernate.custommapping", "1"));
}
public boolean hasDynamicCustomMappings()
{
return "1".equals(getConfiguration().getProperty("xwiki.store.hibernate.custommapping.dynamic", "0"));
}
public String getDefaultSpace(XWikiContext context)
{
String defaultSpace = getXWikiPreference("defaultweb", "", context);
if (StringUtils.isEmpty(defaultSpace)) {
return getConfiguration().getProperty("xwiki.defaultweb", DEFAULT_HOME_SPACE);
}
return defaultSpace;
}
public boolean showViewAction(XWikiContext context)
{
String bl = getXWikiPreference("showviewaction", "", context);
if ("1".equals(bl)) {
return true;
} else if ("0".equals(bl)) {
return false;
}
return "1".equals(getConfiguration().getProperty("xwiki.showviewaction", "1"));
}
public boolean useDefaultAction(XWikiContext context)
{
String bl = getXWikiPreference("usedefaultaction", "", context);
if ("1".equals(bl)) {
return true;
}
if ("0".equals(bl)) {
return false;
}
return "1".equals(getConfiguration().getProperty("xwiki.usedefaultaction", "0"));
}
public String getDefaultPage(XWikiContext context)
{
String defaultPage = getXWikiPreference("defaultpage", "", context);
if (StringUtils.isEmpty(defaultPage)) {
return getConfiguration().getProperty("xwiki.defaultpage", DEFAULT_SPACE_HOMEPAGE);
}
return defaultPage;
}
public boolean hasEditComment(XWikiContext context)
{
String bl = getXWikiPreference("editcomment", "", context);
if ("1".equals(bl)) {
return true;
}
if ("0".equals(bl)) {
return false;
}
return "1".equals(getConfiguration().getProperty("xwiki.editcomment", "0"));
}
public boolean isEditCommentFieldHidden(XWikiContext context)
{
String bl = getXWikiPreference("editcomment_hidden", "", context);
if ("1".equals(bl)) {
return true;
}
if ("0".equals(bl)) {
return false;
}
return "1".equals(getConfiguration().getProperty("xwiki.editcomment.hidden", "0"));
}
public boolean isEditCommentSuggested(XWikiContext context)
{
String bl = getXWikiPreference("editcomment_suggested", "", context);
if ("1".equals(bl)) {
return true;
}
if ("0".equals(bl)) {
return false;
}
return "1".equals(getConfiguration().getProperty("xwiki.editcomment.suggested", "0"));
}
public boolean isEditCommentMandatory(XWikiContext context)
{
String bl = getXWikiPreference("editcomment_mandatory", "", context);
if ("1".equals(bl)) {
return true;
}
if ("0".equals(bl)) {
return false;
}
return "1".equals(getConfiguration().getProperty("xwiki.editcomment.mandatory", "0"));
}
/**
* @see com.xpn.xwiki.api.XWiki#hasMinorEdit()
*/
public boolean hasMinorEdit(XWikiContext context)
{
String bl = getXWikiPreference("minoredit", "", context);
if ("1".equals(bl)) {
return true;
}
if ("0".equals(bl)) {
return false;
}
return "1".equals(getConfiguration().getProperty("xwiki.minoredit", "1"));
}
/**
* @see com.xpn.xwiki.api.XWiki#hasRecycleBin()
* @param context see {@link XWikiContext}
*/
public boolean hasRecycleBin(XWikiContext context)
{
return "1".equals(getConfiguration().getProperty("xwiki.recyclebin", "1"));
}
/**
* Indicates whether deleted attachments are stored in a recycle bin or not. This can be configured using the key
* <var>storage.attachment.recyclebin</var>.
*
* @param context see {@link XWikiContext}
*/
public boolean hasAttachmentRecycleBin(XWikiContext context)
{
return "1".equals(getConfiguration().getProperty("storage.attachment.recyclebin", "1"));
}
/**
* @deprecated use {@link XWikiDocument#rename(String, XWikiContext)} instead
*/
@Deprecated
public XWikiDocument renamePage(XWikiDocument doc, String newFullName, XWikiContext context) throws XWikiException
{
if (context.getWiki().exists(newFullName, context)) {
XWikiDocument delDoc = context.getWiki().getDocument(newFullName, context);
context.getWiki().deleteDocument(delDoc, context);
}
XWikiDocument renamedDoc = doc.copyDocument(newFullName, context);
saveDocument(renamedDoc, context);
renamedDoc.saveAllAttachments(context);
deleteDocument(doc, context);
return renamedDoc;
}
/**
* @deprecated use {@link XWikiDocument#rename(String, XWikiContext)} instead
*/
@Deprecated
public XWikiDocument renamePage(XWikiDocument doc, XWikiContext context, String newFullName) throws XWikiException
{
return renamePage(doc, newFullName, context);
}
/**
* @since 2.2M2
*/
public BaseClass getXClass(DocumentReference documentReference, XWikiContext context) throws XWikiException
{
// Used to avoid recursive loading of documents if there are recursives usage of classes
BaseClass bclass = context.getBaseClass(documentReference);
if (bclass != null) {
return bclass;
}
return getDocument(documentReference, context).getXClass();
}
/**
* @deprecated since 2.2M2 use {@link #getXClass(DocumentReference, XWikiContext)}
*/
@Deprecated
public BaseClass getClass(String fullName, XWikiContext context) throws XWikiException
{
DocumentReference reference = null;
if (StringUtils.isNotEmpty(fullName)) {
reference = getCurrentMixedDocumentReferenceResolver().resolve(fullName);
}
return getXClass(reference, context);
}
public String getEditorPreference(XWikiContext context)
{
String defaultSyntaxContentEditor = getEditConfiguration().getDefaultEditor(SyntaxContent.class);
return defaultSyntaxContentEditor == null ? "" : defaultSyntaxContentEditor.toLowerCase();
}
/**
* Privileged API to retrieve an object instantiated from groovy code in a String. Note that Groovy scripts
* compilation is cached.
*
* @param script the Groovy class definition string (public class MyClass { ... })
* @return An object instantiating this class
* @throws XWikiException
*/
public Object parseGroovyFromString(String script, XWikiContext xcontext) throws XWikiException
{
return getParseGroovyFromString().parseGroovyFromString(script, xcontext);
}
/**
* Privileged API to retrieve an object instantiated from groovy code in a String, using a classloader including all
* JAR files located in the passed page as attachments. Note that Groovy scripts compilation is cached
*
* @param script the Groovy class definition string (public class MyClass { ... })
* @return An object instantiating this class
* @throws XWikiException
*/
public Object parseGroovyFromString(String script, String jarWikiPage, XWikiContext xcontext) throws XWikiException
{
XWikiPageClassLoader pcl = new XWikiPageClassLoader(jarWikiPage, xcontext);
Object prevParentClassLoader = xcontext.get("parentclassloader");
try {
xcontext.put("parentclassloader", pcl);
return parseGroovyFromString(script, xcontext);
} finally {
if (prevParentClassLoader == null) {
xcontext.remove("parentclassloader");
} else {
xcontext.put("parentclassloader", prevParentClassLoader);
}
}
}
public Object parseGroovyFromPage(String fullname, XWikiContext context) throws XWikiException
{
return parseGroovyFromString(context.getWiki().getDocument(fullname, context).getContent(), context);
}
public Object parseGroovyFromPage(String fullName, String jarWikiPage, XWikiContext context) throws XWikiException
{
return parseGroovyFromString(context.getWiki().getDocument(fullName, context).getContent(), jarWikiPage,
context);
}
public String getMacroList(XWikiContext context)
{
String macrosmapping = "";
XWiki xwiki = context.getWiki();
try {
macrosmapping = getResourceContent(MACROS_FILE);
} catch (IOException e) {
}
macrosmapping += "\r\n" + xwiki.getXWikiPreference("macros_mapping", "", context);
return macrosmapping;
}
// This functions adds an object from an new object creation form
public BaseObject getObjectFromRequest(String className, XWikiContext context) throws XWikiException
{
Map<String, String[]> map = Util.getObject(context.getRequest(), className);
BaseClass bclass = context.getWiki().getClass(className, context);
BaseObject newobject = (BaseObject) bclass.fromMap(map, context);
return newobject;
}
public String getConvertingUserNameType(XWikiContext context)
{
if (StringUtils.isNotBlank(context.getWiki().getXWikiPreference("convertmail", context))) {
return context.getWiki().getXWikiPreference("convertmail", "0", context);
}
return getConfiguration().getProperty("xwiki.authentication.convertemail", "0");
}
public String convertUsername(String username, XWikiContext context)
{
if (username == null) {
return null;
}
if (getConvertingUserNameType(context).equals("1") && (username.indexOf('@') != -1)) {
String id = "" + username.hashCode();
id = id.replace("-", "");
if (username.length() > 1) {
int i1 = username.indexOf('@');
id = "" + username.charAt(0) + username.substring(i1 + 1, i1 + 2)
+ username.charAt(username.length() - 1) + id;
}
return id;
} else if (getConvertingUserNameType(context).equals("2")) {
return username.replaceAll("[\\.\\@]", "_");
} else {
return username;
}
}
public boolean hasSectionEdit(XWikiContext context)
{
return getConfiguration().getProperty("xwiki.section.edit", 0) == 1;
}
/**
* @return The maximum section depth for which section editing is available. This can be customized through the
* {@code xwiki.section.depth} configuration property. Defaults to 2 when not defined.
*/
public long getSectionEditingDepth()
{
return getConfiguration().getProperty("xwiki.section.depth", 2L);
}
public String getWysiwygToolbars(XWikiContext context)
{
return getConfiguration().getProperty("xwiki.wysiwyg.toolbars", "");
}
public String clearName(String name, XWikiContext context)
{
return clearName(name, true, true, context);
}
public String clearName(String name, boolean stripDots, boolean ascii, XWikiContext context)
{
String temp = name;
temp = temp.replaceAll(
"[\u00c0\u00c1\u00c2\u00c3\u00c4\u00c5\u0100\u0102\u0104\u01cd\u01de\u01e0\u01fa\u0200\u0202\u0226]", "A");
temp = temp.replaceAll(
"[\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5\u0101\u0103\u0105\u01ce\u01df\u01e1\u01fb\u0201\u0203\u0227]", "a");
temp = temp.replaceAll("[\u00c6\u01e2\u01fc]", "AE");
temp = temp.replaceAll("[\u00e6\u01e3\u01fd]", "ae");
temp = temp.replaceAll("[\u008c\u0152]", "OE");
temp = temp.replaceAll("[\u009c\u0153]", "oe");
temp = temp.replaceAll("[\u00c7\u0106\u0108\u010a\u010c]", "C");
temp = temp.replaceAll("[\u00e7\u0107\u0109\u010b\u010d]", "c");
temp = temp.replaceAll("[\u00d0\u010e\u0110]", "D");
temp = temp.replaceAll("[\u00f0\u010f\u0111]", "d");
temp = temp.replaceAll("[\u00c8\u00c9\u00ca\u00cb\u0112\u0114\u0116\u0118\u011a\u0204\u0206\u0228]", "E");
temp = temp.replaceAll("[\u00e8\u00e9\u00ea\u00eb\u0113\u0115\u0117\u0119\u011b\u01dd\u0205\u0207\u0229]", "e");
temp = temp.replaceAll("[\u011c\u011e\u0120\u0122\u01e4\u01e6\u01f4]", "G");
temp = temp.replaceAll("[\u011d\u011f\u0121\u0123\u01e5\u01e7\u01f5]", "g");
temp = temp.replaceAll("[\u0124\u0126\u021e]", "H");
temp = temp.replaceAll("[\u0125\u0127\u021f]", "h");
temp = temp.replaceAll("[\u00cc\u00cd\u00ce\u00cf\u0128\u012a\u012c\u012e\u0130\u01cf\u0208\u020a]", "I");
temp = temp.replaceAll("[\u00ec\u00ed\u00ee\u00ef\u0129\u012b\u012d\u012f\u0131\u01d0\u0209\u020b]", "i");
temp = temp.replaceAll("[\u0132]", "IJ");
temp = temp.replaceAll("[\u0133]", "ij");
temp = temp.replaceAll("[\u0134]", "J");
temp = temp.replaceAll("[\u0135]", "j");
temp = temp.replaceAll("[\u0136\u01e8]", "K");
temp = temp.replaceAll("[\u0137\u0138\u01e9]", "k");
temp = temp.replaceAll("[\u0139\u013b\u013d\u013f\u0141]", "L");
temp = temp.replaceAll("[\u013a\u013c\u013e\u0140\u0142\u0234]", "l");
temp = temp.replaceAll("[\u00d1\u0143\u0145\u0147\u014a\u01f8]", "N");
temp = temp.replaceAll("[\u00f1\u0144\u0146\u0148\u0149\u014b\u01f9\u0235]", "n");
temp = temp.replaceAll(
"[\u00d2\u00d3\u00d4\u00d5\u00d6\u00d8\u014c\u014e\u0150\u01d1\u01ea\u01ec\u01fe\u020c\u020e\u022a\u022c"
+ "\u022e\u0230]",
"O");
temp = temp.replaceAll(
"[\u00f2\u00f3\u00f4\u00f5\u00f6\u00f8\u014d\u014f\u0151\u01d2\u01eb\u01ed\u01ff\u020d\u020f\u022b\u022d"
+ "\u022f\u0231]",
"o");
temp = temp.replaceAll("[\u0156\u0158\u0210\u0212]", "R");
temp = temp.replaceAll("[\u0157\u0159\u0211\u0213]", "r");
temp = temp.replaceAll("[\u015a\u015c\u015e\u0160\u0218]", "S");
temp = temp.replaceAll("[\u015b\u015d\u015f\u0161\u0219]", "s");
temp = temp.replaceAll("[\u00de\u0162\u0164\u0166\u021a]", "T");
temp = temp.replaceAll("[\u00fe\u0163\u0165\u0167\u021b\u0236]", "t");
temp = temp.replaceAll(
"[\u00d9\u00da\u00db\u00dc\u0168\u016a\u016c\u016e\u0170\u0172\u01d3\u01d5\u01d7\u01d9\u01db\u0214\u0216]",
"U");
temp = temp.replaceAll(
"[\u00f9\u00fa\u00fb\u00fc\u0169\u016b\u016d\u016f\u0171\u0173\u01d4\u01d6\u01d8\u01da\u01dc\u0215\u0217]",
"u");
temp = temp.replaceAll("[\u0174]", "W");
temp = temp.replaceAll("[\u0175]", "w");
temp = temp.replaceAll("[\u00dd\u0176\u0178\u0232]", "Y");
temp = temp.replaceAll("[\u00fd\u00ff\u0177\u0233]", "y");
temp = temp.replaceAll("[\u0179\u017b\u017d]", "Z");
temp = temp.replaceAll("[\u017a\u017c\u017e]", "z");
temp = temp.replaceAll("[\u00df]", "SS");
temp = temp.replaceAll("[_':,;\\\\/]", " ");
name = temp;
name = name.replaceAll("\\s+", "");
name = name.replaceAll("[\\(\\)]", " ");
if (stripDots) {
name = name.replaceAll("[\\.]", "");
}
if (ascii) {
name = name.replaceAll("[^a-zA-Z0-9\\-_\\.]", "");
}
if (name.length() > 250) {
name = name.substring(0, 250);
}
return name;
}
public String getUniquePageName(String space, XWikiContext context)
{
String pageName = generateRandomString(16);
return getUniquePageName(space, pageName, context);
}
public String getUniquePageName(String space, String name, XWikiContext context)
{
String pageName = clearName(name, context);
if (exists(space + "." + pageName, context)) {
int i = 0;
while (exists(space + "." + pageName + "_" + i, context)) {
i++;
}
return pageName + "_" + i;
}
return pageName;
}
public PropertyClass getPropertyClassFromName(String propPath, XWikiContext context)
{
int i1 = propPath.indexOf('_');
if (i1 == -1) {
return null;
} else {
String className = propPath.substring(0, i1);
String propName = propPath.substring(i1 + 1);
try {
return (PropertyClass) getDocument(className, context).getXClass().get(propName);
} catch (XWikiException e) {
return null;
}
}
}
public boolean validateDocument(XWikiDocument doc, XWikiContext context) throws XWikiException
{
return doc.validate(context);
}
public String addTooltip(String html, String message, String params, XWikiContext context)
{
StringBuilder buffer = new StringBuilder();
buffer.append("<span class=\"tooltip_span\" onmouseover=\"");
buffer.append(params);
buffer.append("; return escape('");
buffer.append(message.replaceAll("'", "\\'"));
buffer.append("');\">");
buffer.append(html);
buffer.append("</span>");
return buffer.toString();
}
public String addTooltipJS(XWikiContext context)
{
StringBuilder buffer = new StringBuilder();
buffer.append("<script type=\"text/javascript\" src=\"");
buffer.append(getSkinFile("ajax/wzToolTip.js", context));
buffer.append("\"></script>");
// buffer.append("<div id=\"dhtmltooltip\"></div>");
return buffer.toString();
}
public String addTooltip(String html, String message, XWikiContext context)
{
return addTooltip(html, message, "this.WIDTH='300'", context);
}
public void renamePage(String fullName, String newFullName, XWikiContext context) throws XWikiException
{
renamePage(context.getWiki().getDocument(fullName, context), newFullName, context);
}
public String addMandatory(XWikiContext context)
{
String star =
"<span class=\"mandatoryParenthesis\"> (</span><span class=\"mandatoryDot\">∗</span><span class=\"mandatoryParenthesis\">) </span>";
return context.getWiki().getXWikiPreference("mandatory_display", star, context);
}
/**
* @since 2.3M1
*/
public boolean hasVersioning(XWikiContext context)
{
return ("1".equals(getConfiguration().getProperty("xwiki.store.versioning", "1")));
}
public boolean hasAttachmentVersioning(XWikiContext context)
{
return ("1".equals(getConfiguration().getProperty("xwiki.store.attachment.versioning", "1")));
}
public String getExternalAttachmentURL(String fullName, String filename, XWikiContext context)
{
XWikiDocument doc = new XWikiDocument();
doc.setFullName(fullName, context);
return doc.getExternalAttachmentURL(filename, "download", context);
}
public int getMaxRecursiveSpaceChecks(XWikiContext context)
{
int max = getXWikiPreferenceAsInt("rights_maxrecursivespacechecks", -1, context);
if (max == -1) {
return getConfiguration().getProperty("xwiki.rights.maxrecursivespacechecks", 0);
} else {
return max;
}
}
/**
* Restore a document with passed index from recycle bin.
*
* @param doc the document to restore
* @param comment the comment to use when saving the document
* @param context see {@link XWikiContext}
* @throws XWikiException when failing to restore document
* @since 5.4RC1
*/
public void restoreFromRecycleBin(final XWikiDocument doc, String comment, XWikiContext context)
throws XWikiException
{
XWikiDeletedDocument[] deletedDocuments = getRecycleBinStore().getAllDeletedDocuments(doc, context, true);
if (deletedDocuments != null && deletedDocuments.length > 0) {
long index = deletedDocuments[0].getId();
restoreFromRecycleBin(doc, index, comment, context);
}
}
/**
* Restore a document with passed index from recycle bin.
*
* @param doc the document to restore
* @param index the index of the document in the recycle bin
* @param comment the comment to use when saving the document
* @param context see {@link XWikiContext}
* @throws XWikiException when failing to restore document
* @since 5.4RC1
* @deprecated since 9.4RC1. Use {@link #restoreFromRecycleBin(long, String, XWikiContext)} instead.
*/
@Deprecated
public void restoreFromRecycleBin(final XWikiDocument doc, long index, String comment, XWikiContext context)
throws XWikiException
{
restoreFromRecycleBin(index, comment, context);
}
/**
* Restore a document with passed index from recycle bin.
*
* @param index the index of the document in the recycle bin
* @param comment the comment to use when saving the document
* @param context see {@link XWikiContext}
* @throws XWikiException when failing to restore document
* @since 9.4RC1
*/
public void restoreFromRecycleBin(long index, String comment, XWikiContext context) throws XWikiException
{
XWikiDocument newdoc = getRecycleBinStore().restoreFromRecycleBin(index, context, true);
saveDocument(newdoc, comment, context);
getRecycleBinStore().deleteFromRecycleBin(index, context, true);
}
public XWikiDocument rollback(final XWikiDocument tdoc, String rev, XWikiContext context) throws XWikiException
{
LOGGER.debug("Rolling back [" + tdoc + "] to version " + rev);
// Let's clone rolledbackDoc since we might modify it
XWikiDocument rolledbackDoc = getDocument(tdoc, rev, context).clone();
if ("1".equals(getConfiguration().getProperty("xwiki.store.rollbackattachmentwithdocuments", "1"))) {
// Attachment handling strategy:
// - Two lists: Old Attachments, Current Attachments
// Goals:
// 1. Attachments that are only in OA must be restored from the trash
// 2. Attachments that are only in CA must be sent to the trash
// 3. Attachments that are in both lists should be reverted to the right version
// 4. Gotcha: deleted and re-uploaded attachments should be both trashed and restored.
// Plan:
// - Construct two lists: to restore, to revert
// - Iterate over OA.
// -- If the attachment is not in CA, add it to the restore list
// -- If it is in CA, but the date of the first version of the current attachment is after the date of the
// restored document version, add it the restore & move the current attachment to the recycle bin
// -- Otherwise, add it to the revert list
// - Iterate over CA
// -- If the attachment is not in OA, delete it
List<XWikiAttachment> oldAttachments = rolledbackDoc.getAttachmentList();
List<XWikiAttachment> currentAttachments = tdoc.getAttachmentList();
List<XWikiAttachment> toRestore = new ArrayList<>();
List<XWikiAttachment> toRevert = new ArrayList<>();
// First step, determine what to do with each attachment
LOGGER.debug("Checking attachments");
for (XWikiAttachment oldAttachment : oldAttachments) {
String filename = oldAttachment.getFilename();
XWikiAttachment equivalentAttachment = tdoc.getAttachment(filename);
if (equivalentAttachment == null) {
// Deleted attachment
LOGGER.debug("Deleted attachment: " + filename);
toRestore.add(oldAttachment);
continue;
}
XWikiAttachment equivalentAttachmentRevision =
equivalentAttachment.getAttachmentRevision(oldAttachment.getVersion(), context);
// We compare the number of milliseconds instead of the date objects directly because Hibernate can
// return java.sql.Timestamp for date fields and the JavaDoc says that Timestamp.equals(Object) doesn't
// return true if the passed value is a java.util.Date object with the same number of milliseconds
// because the nanoseconds component of the passed date is unknown.
if (equivalentAttachmentRevision == null
|| equivalentAttachmentRevision.getDate().getTime() != oldAttachment.getDate().getTime()) {
// Recreated attachment
LOGGER.debug("Recreated attachment: " + filename);
// If the attachment trash is not available, don't lose the existing attachment
if (getAttachmentRecycleBinStore() != null) {
getAttachmentRecycleBinStore().saveToRecycleBin(equivalentAttachment, context.getUser(),
new Date(), context, true);
toRestore.add(oldAttachment);
}
continue;
}
if (!StringUtils.equals(oldAttachment.getVersion(), equivalentAttachment.getVersion())) {
// Updated attachment
LOGGER.debug("Updated attachment: " + filename);
toRevert.add(equivalentAttachment);
}
}
for (XWikiAttachment attachment : currentAttachments) {
if (rolledbackDoc.getAttachment(attachment.getFilename()) == null) {
LOGGER.debug("New attachment: " + attachment.getFilename());
// XWikiDocument#save() is actually the only way to delete an attachment cleanly
rolledbackDoc.getAttachmentsToRemove().add(new XWikiAttachmentToRemove(attachment, true));
}
}
// Second step, treat each affected attachment
// Revert updated attachments to the old version
for (XWikiAttachment attachmentToRevert : toRevert) {
String oldAttachmentVersion =
rolledbackDoc.getAttachment(attachmentToRevert.getFilename()).getVersion();
XWikiAttachment oldAttachmentRevision =
attachmentToRevert.getAttachmentRevision(oldAttachmentVersion, context);
if (oldAttachmentRevision == null) {
// Previous version is lost, just leave the current version in place
replaceAttachmentInPlace(rolledbackDoc, attachmentToRevert);
continue;
}
// We can't just leave the old version in place, since it will break the revision history, given the
// current implementation, so we set the attachment version to the most recent version, mark the content
// as dirty, and the storage will automatically bump up the version number.
// This is a hack, to be fixed once the storage doesn't take care of updating the history and version,
// and once the current attachment version can point to an existing version from the history.
oldAttachmentRevision.setVersion(attachmentToRevert.getVersion());
oldAttachmentRevision.setMetaDataDirty(true);
oldAttachmentRevision.getAttachment_content().setContentDirty(true);
replaceAttachmentInPlace(rolledbackDoc, oldAttachmentRevision);
}
// Restore deleted attachments from the trash
if (getAttachmentRecycleBinStore() != null) {
for (XWikiAttachment attachmentToRestore : toRestore) {
// There might be multiple versions of the attachment in the trash, search for the right one
List<DeletedAttachment> deletedVariants =
getAttachmentRecycleBinStore().getAllDeletedAttachments(attachmentToRestore, context, true);
DeletedAttachment correctVariant = null;
for (DeletedAttachment variant : deletedVariants) { // Reverse chronological order
if (variant.getDate().before(rolledbackDoc.getDate())) {
break;
}
correctVariant = variant;
}
if (correctVariant == null) {
// Not found in the trash, nothing left to do
continue;
}
XWikiAttachment restoredAttachment = correctVariant.restoreAttachment(null, context);
XWikiAttachment restoredAttachmentRevision =
restoredAttachment.getAttachmentRevision(attachmentToRestore.getVersion(), context);
if (restoredAttachmentRevision != null) {
restoredAttachmentRevision.setAttachment_archive(restoredAttachment.getAttachment_archive());
restoredAttachmentRevision.getAttachment_archive().setAttachment(restoredAttachmentRevision);
restoredAttachmentRevision.setVersion(restoredAttachment.getVersion());
restoredAttachmentRevision.setMetaDataDirty(true);
restoredAttachmentRevision.getAttachment_content().setContentDirty(true);
replaceAttachmentInPlace(rolledbackDoc, restoredAttachmentRevision);
} else {
// This particular version is lost, update to the one available
replaceAttachmentInPlace(rolledbackDoc, restoredAttachment);
}
}
} else {
// No trash, can't restore. Remove the attachment references, so that the document is not broken
for (XWikiAttachment attachmentToRestore : toRestore) {
rolledbackDoc.getAttachmentList().remove(attachmentToRestore);
}
}
}
// Special treatment for deleted objects
rolledbackDoc.addXObjectsToRemoveFromVersion(tdoc);
// now we save the final document..
rolledbackDoc.setOriginalDocument(tdoc);
rolledbackDoc.setAuthorReference(context.getUserReference());
rolledbackDoc.setRCSVersion(tdoc.getRCSVersion());
rolledbackDoc.setVersion(tdoc.getVersion());
rolledbackDoc.setContentDirty(true);
ObservationManager om = getObservationManager();
if (om != null) {
// Notify listeners about the document that is going to be rolled back.
// Note that for the moment the event being send is a bridge event, as we are still passing around
// an XWikiDocument as source and an XWikiContext as data.
om.notify(new DocumentRollingBackEvent(rolledbackDoc.getDocumentReference(), rev), rolledbackDoc, context);
}
saveDocument(rolledbackDoc, localizePlainOrKey("core.comment.rollback", rev), context);
// Since the the store resets the original document, we need to temporarily put it back to send notifications.
XWikiDocument newOriginalDocument = rolledbackDoc.getOriginalDocument();
rolledbackDoc.setOriginalDocument(tdoc);
try {
if (om != null) {
// Notify listeners about the document that was rolled back.
// Note that for the moment the event being send is a bridge event, as we are still passing around an
// XWikiDocument as source and an XWikiContext as data.
om.notify(new DocumentRolledBackEvent(rolledbackDoc.getDocumentReference(), rev), rolledbackDoc,
context);
}
} finally {
rolledbackDoc.setOriginalDocument(newOriginalDocument);
}
return rolledbackDoc;
}
private void replaceAttachmentInPlace(XWikiDocument doc, XWikiAttachment attachment)
{
for (ListIterator<XWikiAttachment> it = doc.getAttachmentList().listIterator(); it.hasNext();) {
if (StringUtils.equals(it.next().getFilename(), attachment.getFilename())) {
it.remove();
it.add(attachment);
break;
}
}
}
/**
* @return the ids of configured syntaxes for this wiki (e.g. {@code xwiki/2.0}, {@code xwiki/2.1},
* {@code mediawiki/1.0}, etc)
* @deprecated since 8.2M1, use the XWiki Rendering Configuration component or the Rendering Script Service one
* instead
*/
@Deprecated
public List<String> getConfiguredSyntaxes()
{
return this.configuredSyntaxes;
}
/**
* @return the syntax id of the syntax to use when creating new documents
*/
public String getDefaultDocumentSyntax()
{
// TODO: Fix this method to return a Syntax object instead of a String
return getDefaultDocumentSyntaxInternal().toIdString();
}
/**
* @return the syntax to use when creating new documents
*/
private Syntax getDefaultDocumentSyntaxInternal()
{
return Utils.getComponent(CoreConfiguration.class).getDefaultDocumentSyntax();
}
/**
* Get the syntax of the content currently being executed.
* <p>
* The document currently being executed is not the same than the actual content syntax since the executed code
* might come from an included page or some macro that change the context syntax. The same logic used inside
* rendering macros is used (see {@link org.xwiki.rendering.macro.MacroContentParser}).
* <p>
* If the current document can't be found, the method assume that the executed document is the context document
* (it's generally the case when a document is directly rendered with
* {@link XWikiDocument#getRenderedContent(XWikiContext)} for example).
*
* @param defaultSyntaxId the default value to return if no document can be found
* @return the syntax identifier
*/
public String getCurrentContentSyntaxId(String defaultSyntaxId, XWikiContext context)
{
String syntaxId = getCurrentContentSyntaxIdInternal(context);
if (syntaxId == null) {
syntaxId = defaultSyntaxId;
}
return syntaxId;
}
/**
* Get the syntax of the content currently being executed.
* <p>
* The document currently being executed is not the same than the actual content syntax since the executed code
* might come from an included page or some macro that change the context syntax. The same logic used inside
* rendering macros is used (see {@link org.xwiki.rendering.macro.MacroContentParser}).
* <p>
* If the current document can't be found, the method assume that the executed document is the context document
* (it's generally the case when a document is directly rendered with
* {@link XWikiDocument#getRenderedContent(XWikiContext)} for example).
*
* @return the syntax identifier
*/
public String getCurrentContentSyntaxId(XWikiContext context)
{
String syntaxId = getCurrentContentSyntaxIdInternal(context);
if (syntaxId == null) {
throw new RuntimeException("Cannot get the current syntax since there's no current document set");
}
return syntaxId;
}
/**
* Get the syntax of the content currently being executed.
* <p>
* The document currently being executed is not the same than the actual content syntax since the executed code
* might come from an included page or some macro that change the context syntax. The same logic used inside
* rendering macros is used (see {@link org.xwiki.rendering.macro.MacroContentParser}).
* <p>
* If the current document can't be found, the method assume that the executed document is the context document
* (it's generally the case when a document is directly rendered with
* {@link XWikiDocument#getRenderedContent(XWikiContext)} for example).
*
* @return the syntax identifier
*/
private String getCurrentContentSyntaxIdInternal(XWikiContext context)
{
Syntax syntax = getCurrentContentSyntaxInternal(context);
return syntax != null ? syntax.toIdString() : null;
}
/**
* Get the syntax of the code currently being executed.
* <p>
* The document currently being executed is not the same than the actual content syntax since the executed code
* might come from an included page or some macro that change the context syntax. The same logic used inside
* rendering macros is used (see {@link org.xwiki.rendering.macro.MacroContentParser}).
* <p>
* If the current document can't be found, the method assume that the executed document is the context document
* (it's generally the case when a document is directly rendered with
* {@link XWikiDocument#getRenderedContent(XWikiContext)} for example).
*
* @return the syntax
*/
private Syntax getCurrentContentSyntaxInternal(XWikiContext context)
{
Syntax syntax = null;
// Try to find the current syntax
if (getRenderingContext() != null) {
Block curentBlock = getRenderingContext().getCurrentBlock();
if (curentBlock != null) {
MetaDataBlock metaDataBlock =
curentBlock.getFirstBlock(new MetadataBlockMatcher(MetaData.SYNTAX), Axes.ANCESTOR_OR_SELF);
if (metaDataBlock != null) {
return (Syntax) metaDataBlock.getMetaData().getMetaData(MetaData.SYNTAX);
}
}
}
// Fallback on secure and current document in the context
if (context.get("sdoc") != null) {
// The content document
syntax = ((XWikiDocument) context.get("sdoc")).getSyntax();
} else if (context.getDoc() != null) {
// The context document
syntax = context.getDoc().getSyntax();
}
return syntax;
}
/**
* @return true if title handling should be using the compatibility mode or not. When the compatibility mode is
* active, if the document's content first header (level 1 or level 2) matches the document's title the
* first header is stripped.
*/
public boolean isTitleInCompatibilityMode()
{
return "1".equals(getConfiguration().getProperty("xwiki.title.compatibility", "0"));
}
@Override
public void onEvent(Event event, Object source, Object data)
{
if (event instanceof WikiDeletedEvent) {
// A wiki has been deleted
onWikiDeletedEvent((WikiDeletedEvent) event);
} else if (event instanceof ComponentDescriptorAddedEvent) {
// A new mandatory document initializer has been installed
onMandatoryDocumentInitializerAdded((ComponentDescriptorAddedEvent) event, (ComponentManager) source);
} else {
// Document modifications
XWikiDocument doc = (XWikiDocument) source;
XWikiContext context = (XWikiContext) data;
if (event instanceof XObjectPropertyEvent) {
EntityReference reference = ((XObjectPropertyEvent) event).getReference();
String modifiedProperty = reference.getName();
if ("backlinks".equals(modifiedProperty)) {
this.hasBacklinks = doc.getXObject((ObjectReference) reference.getParent()).getIntValue("backlinks",
getConfiguration().getProperty("xwiki.backlinks", 0)) == 1;
}
}
}
}
private void onWikiDeletedEvent(WikiDeletedEvent event)
{
this.initializedWikis.remove(event.getWikiId());
}
private void onMandatoryDocumentInitializerAdded(ComponentDescriptorAddedEvent event,
ComponentManager componentManager)
{
String namespace;
if (componentManager instanceof NamespacedComponentManager) {
namespace = ((NamespacedComponentManager) componentManager).getNamespace();
} else {
namespace = null;
}
MandatoryDocumentInitializer initializer;
try {
initializer = componentManager.getInstance(MandatoryDocumentInitializer.class, event.getRoleHint());
XWikiContext context = getXWikiContext();
if (namespace == null) {
// Initialize in already initialized wikis (will be initialized in others when they are initialized)
for (String wiki : this.initializedWikis.keySet()) {
initializeMandatoryDocument(wiki, initializer, context);
}
} else if (namespace.startsWith("wiki:")) {
// Initialize in the wiki where the extension is installed
initializeMandatoryDocument(namespace.substring("wiki:".length()), initializer, context);
}
} catch (ComponentLookupException e) {
LOGGER.error("Failed to lookup mandatory document initializer", e);
}
}
/**
* The reference to match properties "plugins" and "backlinks" of class XWiki.XWikiPreference on whatever wiki.
*/
private static final RegexEntityReference XWIKIPREFERENCE_PROPERTY_REFERENCE =
XWikiPreferencesDocumentInitializer.OBJECT_REFERENCE;
private static final List<Event> LISTENER_EVENTS =
Arrays.<Event>asList(new XObjectPropertyAddedEvent(XWIKIPREFERENCE_PROPERTY_REFERENCE),
new XObjectPropertyDeletedEvent(XWIKIPREFERENCE_PROPERTY_REFERENCE),
new XObjectPropertyUpdatedEvent(XWIKIPREFERENCE_PROPERTY_REFERENCE), new WikiDeletedEvent(),
new ComponentDescriptorAddedEvent(MandatoryDocumentInitializer.class));
@Override
public List<Event> getEvents()
{
return LISTENER_EVENTS;
}
@Override
public String getName()
{
return "xwiki-core";
}
/**
* Return the document reference to the wiki preferences.
*
* @param context see {@link XWikiContext}
* @since 4.3M2
*/
private DocumentReference getPreferencesDocumentReference(XWikiContext context)
{
String database = context.getWikiId();
EntityReference spaceReference;
if (database != null) {
spaceReference = new EntityReference(SYSTEM_SPACE, EntityType.SPACE, new WikiReference(database));
} else {
spaceReference = getCurrentMixedEntityReferenceResolver().resolve(SYSTEM_SPACE, EntityType.SPACE);
}
return new DocumentReference("XWikiPreferences", new SpaceReference(spaceReference));
}
/**
* Search attachments by passing HQL where clause values as parameters. You can specify properties of the "attach"
* (the attachment) or "doc" (the document it is attached to)
*
* @param parametrizedSqlClause The HQL where clause. For example {@code where doc.fullName
* <> ? and (attach.author = ? or (attach.filename = ? and doc.space = ?))}
* @param checkRight if true, only return attachments in documents which the "current user" has permission to view.
* @param nb The number of rows to return. If 0 then all rows are returned
* @param start The number of rows to skip at the beginning.
* @param parameterValues A {@link java.util.List} of the where clause values that replace the question marks (?)
* @param context see {@link XWikiContext}
* @return A List of {@link XWikiAttachment} objects.
* @throws XWikiException in case of error while performing the query
* @see com.xpn.xwiki.store.XWikiStoreInterface#searchDocuments(String, int, int, java.util.List, XWikiContext)
* @since 5.0M2
*/
public List<XWikiAttachment> searchAttachments(String parametrizedSqlClause, boolean checkRight, int nb, int start,
List<?> parameterValues, XWikiContext context) throws XWikiException
{
parametrizedSqlClause = parametrizedSqlClause.trim().replaceFirst("^and ", "").replaceFirst("^where ", "");
// Get the attachment filenames and document fullNames
List<java.lang.Object[]> results = this.getStore().search(
"select attach.filename, doc.fullName from XWikiAttachment attach, XWikiDocument doc where doc.id = attach.docId and "
+ parametrizedSqlClause,
nb, start, parameterValues, context);
HashMap<String, List<String>> filenamesByDocFullName = new HashMap<String, List<String>>();
// Put each attachment name with the document name it belongs to
for (int i = 0; i < results.size(); i++) {
String filename = (String) results.get(i)[0];
String docFullName = (String) results.get(i)[1];
if (!filenamesByDocFullName.containsKey(docFullName)) {
filenamesByDocFullName.put(docFullName, new ArrayList<String>());
}
filenamesByDocFullName.get(docFullName).add(filename);
}
List<XWikiAttachment> out = new ArrayList<XWikiAttachment>();
// Index through the document names, get relivent attachments
for (Map.Entry<String, List<String>> entry : filenamesByDocFullName.entrySet()) {
String fullName = entry.getKey();
XWikiDocument doc = getDocument(fullName, context);
if (checkRight) {
if (!context.getWiki().getRightService().hasAccessLevel("view", context.getUser(), doc.getFullName(),
context)) {
continue;
}
}
List<String> returnedAttachmentNames = entry.getValue();
for (XWikiAttachment attach : doc.getAttachmentList()) {
if (returnedAttachmentNames.contains(attach.getFilename())) {
out.add(attach);
}
}
}
return out;
}
/**
* Count attachments returned by a given parameterized query
*
* @param parametrizedSqlClause Everything which would follow the "WHERE" in HQL
* @param parameterValues A {@link java.util.List} of the where clause values that replace the question marks (?)
* @param context see {@link XWikiContext}
* @return int number of attachments found.
* @throws XWikiException in event of an exception querying the database
* @see #searchAttachments(String, boolean, int, int, java.util.List, XWikiContext)
* @since 5.0M2
*/
public int countAttachments(String parametrizedSqlClause, List<?> parameterValues, XWikiContext context)
throws XWikiException
{
parametrizedSqlClause = parametrizedSqlClause.trim().replaceFirst("^and ", "").replaceFirst("^where ", "");
List l = getStore().search("select count(attach) from XWikiAttachment attach, XWikiDocument doc where "
+ "attach.docId=doc.id and " + parametrizedSqlClause, 0, 0, parameterValues, context);
return ((Number) l.get(0)).intValue();
}
// Deprecated
/**
* @deprecated since 6.1M2, use {@link XWikiCfgConfigurationSource#getConfigPath()} instead
*/
@Deprecated
public static String getConfigPath() throws NamingException
{
return XWikiCfgConfigurationSource.getConfigPath();
}
/**
* @deprecated since 6.1M3, use {@link #XWiki(XWikiContext)} instead
*/
@Deprecated
public XWiki(XWikiConfig config, XWikiContext context) throws XWikiException
{
this(config, context, null, false);
}
/**
* @deprecated since 6.1M3, use {@link #XWiki(XWikiContext, XWikiEngineContext, boolean)} instead
*/
@Deprecated
public XWiki(XWikiConfig config, XWikiContext context, XWikiEngineContext engine_context, boolean noupdate)
throws XWikiException
{
initXWiki(config, context, engine_context, noupdate);
}
/**
* @deprecated use {@link #XWiki(XWikiContext)} instead
*/
@Deprecated
public XWiki(String xwikicfgpath, XWikiContext context) throws XWikiException
{
this(xwikicfgpath, context, null, false);
}
/**
* @deprecated use {@link #XWiki(XWikiContext, XWikiEngineContext, boolean)} instead
*/
@Deprecated
public XWiki(String xwikicfgpath, XWikiContext context, XWikiEngineContext engine_context, boolean noupdate)
throws XWikiException
{
try {
initXWiki(new XWikiConfig(new FileInputStream(xwikicfgpath)), context, engine_context, noupdate);
} catch (FileNotFoundException e) {
Object[] args = { xwikicfgpath };
throw new XWikiException(XWikiException.MODULE_XWIKI_CONFIG, XWikiException.ERROR_XWIKI_CONFIG_FILENOTFOUND,
"Configuration file {0} not found", e, args);
}
}
/**
* @deprecated use {@link #XWiki(XWikiContext, XWikiEngineContext, boolean)} instead
*/
@Deprecated
public XWiki(InputStream is, XWikiContext context, XWikiEngineContext engine_context) throws XWikiException
{
initXWiki(new XWikiConfig(is), context, engine_context, true);
}
/**
* @deprecated since 6.1M2, use {@link ConfigurationSource} component with hint <code>xwikicfg</code> instead
*/
@Deprecated
public XWikiConfig getConfig()
{
return new XWikiConfigDelegate(getConfiguration());
}
/**
* @deprecated since 6.1M2
*/
@Deprecated
public void setConfig(XWikiConfig config)
{
ConfigurationSource configuration = getConfiguration();
if (configuration instanceof XWikiCfgConfigurationSource) {
((XWikiCfgConfigurationSource) configuration).set(config);
}
}
/**
* @deprecated since 6.1M2, use {@link ConfigurationSource} component with hint <code>xwikicfg</code> instead
*/
@Deprecated
public String Param(String key)
{
return Param(key, null);
}
/**
* @deprecated since 6.1M2, use {@link ConfigurationSource} component with hint <code>xwikicfg</code> instead
*/
@Deprecated
public String Param(String key, String default_value)
{
if (getConfiguration() != null) {
return getConfiguration().getProperty(key, default_value);
}
return default_value;
}
/**
* @deprecated since 6.1M2, use {@link ConfigurationSource} component with hint <code>xwikicfg</code> instead
*/
@Deprecated
public long ParamAsLong(String key)
{
return getConfiguration().getProperty(key, long.class);
}
/**
* @deprecated since 6.1M2, use {@link ConfigurationSource} component with hint <code>xwikicfg</code> instead
*/
@Deprecated
public long ParamAsLong(String key, long default_value)
{
return getConfiguration().getProperty(key, default_value);
}
}